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);
673 * Find the current bootstrap width Grid size
674 * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675 * @returns {String} (xs|sm|md|lg|xl)
678 getGridSize : function()
680 var w = Roo.lib.Dom.getViewWidth();
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
705 "Roo.bootstrap.dash");
708 * Ext JS Library 1.1.1
709 * Copyright(c) 2006-2007, Ext JS, LLC.
711 * Originally Released Under LGPL - original licence link has changed is not relivant.
714 * <script type="text/javascript">
718 // wrappedn so fnCleanup is not in global scope...
720 function fnCleanUp() {
721 var p = Function.prototype;
722 delete p.createSequence;
724 delete p.createDelegate;
725 delete p.createCallback;
726 delete p.createInterceptor;
728 window.detachEvent("onunload", fnCleanUp);
730 window.attachEvent("onunload", fnCleanUp);
737 * These functions are available on every Function object (any JavaScript function).
739 Roo.apply(Function.prototype, {
741 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
742 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
743 * Will create a function that is bound to those 2 args.
744 * @return {Function} The new function
746 createCallback : function(/*args...*/){
747 // make args available, in function below
748 var args = arguments;
751 return method.apply(window, args);
756 * Creates a delegate (callback) that sets the scope to obj.
757 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
758 * Will create a function that is automatically scoped to this.
759 * @param {Object} obj (optional) The object for which the scope is set
760 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
761 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
762 * if a number the args are inserted at the specified position
763 * @return {Function} The new function
765 createDelegate : function(obj, args, appendArgs){
768 var callArgs = args || arguments;
769 if(appendArgs === true){
770 callArgs = Array.prototype.slice.call(arguments, 0);
771 callArgs = callArgs.concat(args);
772 }else if(typeof appendArgs == "number"){
773 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
774 var applyArgs = [appendArgs, 0].concat(args); // create method call params
775 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
777 return method.apply(obj || window, callArgs);
782 * Calls this function after the number of millseconds specified.
783 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
784 * @param {Object} obj (optional) The object for which the scope is set
785 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
786 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
787 * if a number the args are inserted at the specified position
788 * @return {Number} The timeout id that can be used with clearTimeout
790 defer : function(millis, obj, args, appendArgs){
791 var fn = this.createDelegate(obj, args, appendArgs);
793 return setTimeout(fn, millis);
799 * Create a combined function call sequence of the original function + the passed function.
800 * The resulting function returns the results of the original function.
801 * The passed fcn is called with the parameters of the original function
802 * @param {Function} fcn The function to sequence
803 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
804 * @return {Function} The new function
806 createSequence : function(fcn, scope){
807 if(typeof fcn != "function"){
812 var retval = method.apply(this || window, arguments);
813 fcn.apply(scope || this || window, arguments);
819 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
820 * The resulting function returns the results of the original function.
821 * The passed fcn is called with the parameters of the original function.
823 * @param {Function} fcn The function to call before the original
824 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
825 * @return {Function} The new function
827 createInterceptor : function(fcn, scope){
828 if(typeof fcn != "function"){
835 if(fcn.apply(scope || this || window, arguments) === false){
838 return method.apply(this || window, arguments);
844 * Ext JS Library 1.1.1
845 * Copyright(c) 2006-2007, Ext JS, LLC.
847 * Originally Released Under LGPL - original licence link has changed is not relivant.
850 * <script type="text/javascript">
853 Roo.applyIf(String, {
858 * Escapes the passed string for ' and \
859 * @param {String} string The string to escape
860 * @return {String} The escaped string
863 escape : function(string) {
864 return string.replace(/('|\\)/g, "\\$1");
868 * Pads the left side of a string with a specified character. This is especially useful
869 * for normalizing number and date strings. Example usage:
871 var s = String.leftPad('123', 5, '0');
872 // s now contains the string: '00123'
874 * @param {String} string The original string
875 * @param {Number} size The total length of the output string
876 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
877 * @return {String} The padded string
880 leftPad : function (val, size, ch) {
881 var result = new String(val);
882 if(ch === null || ch === undefined || ch === '') {
885 while (result.length < size) {
886 result = ch + result;
892 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
893 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
895 var cls = 'my-class', text = 'Some text';
896 var s = String.format('<div class="{0}">{1}</div>', cls, text);
897 // s now contains the string: '<div class="my-class">Some text</div>'
899 * @param {String} string The tokenized string to be formatted
900 * @param {String} value1 The value to replace token {0}
901 * @param {String} value2 Etc...
902 * @return {String} The formatted string
905 format : function(format){
906 var args = Array.prototype.slice.call(arguments, 1);
907 return format.replace(/\{(\d+)\}/g, function(m, i){
908 return Roo.util.Format.htmlEncode(args[i]);
916 * Utility function that allows you to easily switch a string between two alternating values. The passed value
917 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
918 * they are already different, the first value passed in is returned. Note that this method returns the new value
919 * but does not change the current string.
921 // alternate sort directions
922 sort = sort.toggle('ASC', 'DESC');
924 // instead of conditional logic:
925 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
927 * @param {String} value The value to compare to the current string
928 * @param {String} other The new value to use if the string already equals the first value passed in
929 * @return {String} The new value
932 String.prototype.toggle = function(value, other){
933 return this == value ? other : value;
938 * Remove invalid unicode characters from a string
940 * @return {String} The clean string
942 String.prototype.unicodeClean = function () {
943 return this.replace(/[\s\S]/g,
944 function(character) {
945 if (character.charCodeAt()< 256) {
949 encodeURIComponent(character);
960 * Ext JS Library 1.1.1
961 * Copyright(c) 2006-2007, Ext JS, LLC.
963 * Originally Released Under LGPL - original licence link has changed is not relivant.
966 * <script type="text/javascript">
972 Roo.applyIf(Number.prototype, {
974 * Checks whether or not the current number is within a desired range. If the number is already within the
975 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
976 * exceeded. Note that this method returns the constrained value but does not change the current number.
977 * @param {Number} min The minimum number in the range
978 * @param {Number} max The maximum number in the range
979 * @return {Number} The constrained value if outside the range, otherwise the current value
981 constrain : function(min, max){
982 return Math.min(Math.max(this, min), max);
986 * Ext JS Library 1.1.1
987 * Copyright(c) 2006-2007, Ext JS, LLC.
989 * Originally Released Under LGPL - original licence link has changed is not relivant.
992 * <script type="text/javascript">
997 Roo.applyIf(Array.prototype, {
1000 * Checks whether or not the specified object exists in the array.
1001 * @param {Object} o The object to check for
1002 * @return {Number} The index of o in the array (or -1 if it is not found)
1004 indexOf : function(o){
1005 for (var i = 0, len = this.length; i < len; i++){
1006 if(this[i] == o) { return i; }
1012 * Removes the specified object from the array. If the object is not found nothing happens.
1013 * @param {Object} o The object to remove
1015 remove : function(o){
1016 var index = this.indexOf(o);
1018 this.splice(index, 1);
1022 * Map (JS 1.6 compatibility)
1023 * @param {Function} function to call
1025 map : function(fun )
1027 var len = this.length >>> 0;
1028 if (typeof fun != "function") {
1029 throw new TypeError();
1031 var res = new Array(len);
1032 var thisp = arguments[1];
1033 for (var i = 0; i < len; i++)
1036 res[i] = fun.call(thisp, this[i], i, this);
1044 * @param {Array} o The array to compare to
1045 * @returns {Boolean} true if the same
1047 equals : function(b)
1049 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1056 if (this.length !== b.length) {
1060 // sort?? a.sort().equals(b.sort());
1062 for (var i = 0; i < this.length; ++i) {
1063 if (this[i] !== b[i]) {
1075 Roo.applyIf(Array, {
1079 * @param {Array} o Or Array like object (eg. nodelist)
1086 for (var i =0; i < o.length; i++) {
1095 * Ext JS Library 1.1.1
1096 * Copyright(c) 2006-2007, Ext JS, LLC.
1098 * Originally Released Under LGPL - original licence link has changed is not relivant.
1101 * <script type="text/javascript">
1107 * The date parsing and format syntax is a subset of
1108 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1109 * supported will provide results equivalent to their PHP versions.
1111 * Following is the list of all currently supported formats:
1114 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1116 Format Output Description
1117 ------ ---------- --------------------------------------------------------------
1118 d 10 Day of the month, 2 digits with leading zeros
1119 D Wed A textual representation of a day, three letters
1120 j 10 Day of the month without leading zeros
1121 l Wednesday A full textual representation of the day of the week
1122 S th English ordinal day of month suffix, 2 chars (use with j)
1123 w 3 Numeric representation of the day of the week
1124 z 9 The julian date, or day of the year (0-365)
1125 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1126 F January A full textual representation of the month
1127 m 01 Numeric representation of a month, with leading zeros
1128 M Jan Month name abbreviation, three letters
1129 n 1 Numeric representation of a month, without leading zeros
1130 t 31 Number of days in the given month
1131 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1132 Y 2007 A full numeric representation of a year, 4 digits
1133 y 07 A two digit representation of a year
1134 a pm Lowercase Ante meridiem and Post meridiem
1135 A PM Uppercase Ante meridiem and Post meridiem
1136 g 3 12-hour format of an hour without leading zeros
1137 G 15 24-hour format of an hour without leading zeros
1138 h 03 12-hour format of an hour with leading zeros
1139 H 15 24-hour format of an hour with leading zeros
1140 i 05 Minutes with leading zeros
1141 s 01 Seconds, with leading zeros
1142 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1143 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1144 T CST Timezone setting of the machine running the code
1145 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1148 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1150 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1151 document.write(dt.format('Y-m-d')); //2007-01-10
1152 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1153 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
1156 * Here are some standard date/time patterns that you might find helpful. They
1157 * are not part of the source of Date.js, but to use them you can simply copy this
1158 * block of code into any script that is included after Date.js and they will also become
1159 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1162 ISO8601Long:"Y-m-d H:i:s",
1163 ISO8601Short:"Y-m-d",
1165 LongDate: "l, F d, Y",
1166 FullDateTime: "l, F d, Y g:i:s A",
1169 LongTime: "g:i:s A",
1170 SortableDateTime: "Y-m-d\\TH:i:s",
1171 UniversalSortableDateTime: "Y-m-d H:i:sO",
1178 var dt = new Date();
1179 document.write(dt.format(Date.patterns.ShortDate));
1184 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1185 * They generate precompiled functions from date formats instead of parsing and
1186 * processing the pattern every time you format a date. These functions are available
1187 * on every Date object (any javascript function).
1189 * The original article and download are here:
1190 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1197 Returns the number of milliseconds between this date and date
1198 @param {Date} date (optional) Defaults to now
1199 @return {Number} The diff in milliseconds
1200 @member Date getElapsed
1202 Date.prototype.getElapsed = function(date) {
1203 return Math.abs((date || new Date()).getTime()-this.getTime());
1205 // was in date file..
1209 Date.parseFunctions = {count:0};
1211 Date.parseRegexes = [];
1213 Date.formatFunctions = {count:0};
1216 Date.prototype.dateFormat = function(format) {
1217 if (Date.formatFunctions[format] == null) {
1218 Date.createNewFormat(format);
1220 var func = Date.formatFunctions[format];
1221 return this[func]();
1226 * Formats a date given the supplied format string
1227 * @param {String} format The format string
1228 * @return {String} The formatted date
1231 Date.prototype.format = Date.prototype.dateFormat;
1234 Date.createNewFormat = function(format) {
1235 var funcName = "format" + Date.formatFunctions.count++;
1236 Date.formatFunctions[format] = funcName;
1237 var code = "Date.prototype." + funcName + " = function(){return ";
1238 var special = false;
1240 for (var i = 0; i < format.length; ++i) {
1241 ch = format.charAt(i);
1242 if (!special && ch == "\\") {
1247 code += "'" + String.escape(ch) + "' + ";
1250 code += Date.getFormatCode(ch);
1253 /** eval:var:zzzzzzzzzzzzz */
1254 eval(code.substring(0, code.length - 3) + ";}");
1258 Date.getFormatCode = function(character) {
1259 switch (character) {
1261 return "String.leftPad(this.getDate(), 2, '0') + ";
1263 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1265 return "this.getDate() + ";
1267 return "Date.dayNames[this.getDay()] + ";
1269 return "this.getSuffix() + ";
1271 return "this.getDay() + ";
1273 return "this.getDayOfYear() + ";
1275 return "this.getWeekOfYear() + ";
1277 return "Date.monthNames[this.getMonth()] + ";
1279 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1281 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1283 return "(this.getMonth() + 1) + ";
1285 return "this.getDaysInMonth() + ";
1287 return "(this.isLeapYear() ? 1 : 0) + ";
1289 return "this.getFullYear() + ";
1291 return "('' + this.getFullYear()).substring(2, 4) + ";
1293 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1295 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1297 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1299 return "this.getHours() + ";
1301 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1303 return "String.leftPad(this.getHours(), 2, '0') + ";
1305 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1307 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1309 return "this.getGMTOffset() + ";
1311 return "this.getGMTColonOffset() + ";
1313 return "this.getTimezone() + ";
1315 return "(this.getTimezoneOffset() * -60) + ";
1317 return "'" + String.escape(character) + "' + ";
1322 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1323 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1324 * the date format that is not specified will default to the current date value for that part. Time parts can also
1325 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1326 * string or the parse operation will fail.
1329 //dt = Fri May 25 2007 (current date)
1330 var dt = new Date();
1332 //dt = Thu May 25 2006 (today's month/day in 2006)
1333 dt = Date.parseDate("2006", "Y");
1335 //dt = Sun Jan 15 2006 (all date parts specified)
1336 dt = Date.parseDate("2006-1-15", "Y-m-d");
1338 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1339 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1341 * @param {String} input The unparsed date as a string
1342 * @param {String} format The format the date is in
1343 * @return {Date} The parsed date
1346 Date.parseDate = function(input, format) {
1347 if (Date.parseFunctions[format] == null) {
1348 Date.createParser(format);
1350 var func = Date.parseFunctions[format];
1351 return Date[func](input);
1357 Date.createParser = function(format) {
1358 var funcName = "parse" + Date.parseFunctions.count++;
1359 var regexNum = Date.parseRegexes.length;
1360 var currentGroup = 1;
1361 Date.parseFunctions[format] = funcName;
1363 var code = "Date." + funcName + " = function(input){\n"
1364 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1365 + "var d = new Date();\n"
1366 + "y = d.getFullYear();\n"
1367 + "m = d.getMonth();\n"
1368 + "d = d.getDate();\n"
1369 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1370 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1371 + "if (results && results.length > 0) {";
1374 var special = false;
1376 for (var i = 0; i < format.length; ++i) {
1377 ch = format.charAt(i);
1378 if (!special && ch == "\\") {
1383 regex += String.escape(ch);
1386 var obj = Date.formatCodeToRegex(ch, currentGroup);
1387 currentGroup += obj.g;
1389 if (obj.g && obj.c) {
1395 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1396 + "{v = new Date(y, m, d, h, i, s);}\n"
1397 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1398 + "{v = new Date(y, m, d, h, i);}\n"
1399 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1400 + "{v = new Date(y, m, d, h);}\n"
1401 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1402 + "{v = new Date(y, m, d);}\n"
1403 + "else if (y >= 0 && m >= 0)\n"
1404 + "{v = new Date(y, m);}\n"
1405 + "else if (y >= 0)\n"
1406 + "{v = new Date(y);}\n"
1407 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1408 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1409 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1412 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1413 /** eval:var:zzzzzzzzzzzzz */
1418 Date.formatCodeToRegex = function(character, currentGroup) {
1419 switch (character) {
1423 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1426 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1427 s:"(\\d{1,2})"}; // day of month without leading zeroes
1430 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1431 s:"(\\d{2})"}; // day of month with leading zeroes
1435 s:"(?:" + Date.dayNames.join("|") + ")"};
1439 s:"(?:st|nd|rd|th)"};
1454 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1455 s:"(" + Date.monthNames.join("|") + ")"};
1458 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1459 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1462 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1463 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1466 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1467 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1478 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1482 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1483 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1487 c:"if (results[" + currentGroup + "] == 'am') {\n"
1488 + "if (h == 12) { h = 0; }\n"
1489 + "} else { if (h < 12) { h += 12; }}",
1493 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1494 + "if (h == 12) { h = 0; }\n"
1495 + "} else { if (h < 12) { h += 12; }}",
1500 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1501 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1505 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1506 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1509 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1513 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1518 "o = results[", currentGroup, "];\n",
1519 "var sn = o.substring(0,1);\n", // get + / - sign
1520 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1521 "var mn = o.substring(3,5) % 60;\n", // get minutes
1522 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1523 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1525 s:"([+\-]\\d{2,4})"};
1531 "o = results[", currentGroup, "];\n",
1532 "var sn = o.substring(0,1);\n",
1533 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1534 "var mn = o.substring(4,6) % 60;\n",
1535 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1536 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1542 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1545 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1546 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1547 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1551 s:String.escape(character)};
1556 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1557 * @return {String} The abbreviated timezone name (e.g. 'CST')
1559 Date.prototype.getTimezone = function() {
1560 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1564 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1565 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1567 Date.prototype.getGMTOffset = function() {
1568 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1569 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1570 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1574 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1575 * @return {String} 2-characters representing hours and 2-characters representing minutes
1576 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1578 Date.prototype.getGMTColonOffset = function() {
1579 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1580 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1582 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1586 * Get the numeric day number of the year, adjusted for leap year.
1587 * @return {Number} 0 through 364 (365 in leap years)
1589 Date.prototype.getDayOfYear = function() {
1591 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1592 for (var i = 0; i < this.getMonth(); ++i) {
1593 num += Date.daysInMonth[i];
1595 return num + this.getDate() - 1;
1599 * Get the string representation of the numeric week number of the year
1600 * (equivalent to the format specifier 'W').
1601 * @return {String} '00' through '52'
1603 Date.prototype.getWeekOfYear = function() {
1604 // Skip to Thursday of this week
1605 var now = this.getDayOfYear() + (4 - this.getDay());
1606 // Find the first Thursday of the year
1607 var jan1 = new Date(this.getFullYear(), 0, 1);
1608 var then = (7 - jan1.getDay() + 4);
1609 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1613 * Whether or not the current date is in a leap year.
1614 * @return {Boolean} True if the current date is in a leap year, else false
1616 Date.prototype.isLeapYear = function() {
1617 var year = this.getFullYear();
1618 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1622 * Get the first day of the current month, adjusted for leap year. The returned value
1623 * is the numeric day index within the week (0-6) which can be used in conjunction with
1624 * the {@link #monthNames} array to retrieve the textual day name.
1627 var dt = new Date('1/10/2007');
1628 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1630 * @return {Number} The day number (0-6)
1632 Date.prototype.getFirstDayOfMonth = function() {
1633 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1634 return (day < 0) ? (day + 7) : day;
1638 * Get the last day of the current month, adjusted for leap year. The returned value
1639 * is the numeric day index within the week (0-6) which can be used in conjunction with
1640 * the {@link #monthNames} array to retrieve the textual day name.
1643 var dt = new Date('1/10/2007');
1644 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1646 * @return {Number} The day number (0-6)
1648 Date.prototype.getLastDayOfMonth = function() {
1649 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1650 return (day < 0) ? (day + 7) : day;
1655 * Get the first date of this date's month
1658 Date.prototype.getFirstDateOfMonth = function() {
1659 return new Date(this.getFullYear(), this.getMonth(), 1);
1663 * Get the last date of this date's month
1666 Date.prototype.getLastDateOfMonth = function() {
1667 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1670 * Get the number of days in the current month, adjusted for leap year.
1671 * @return {Number} The number of days in the month
1673 Date.prototype.getDaysInMonth = function() {
1674 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1675 return Date.daysInMonth[this.getMonth()];
1679 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1680 * @return {String} 'st, 'nd', 'rd' or 'th'
1682 Date.prototype.getSuffix = function() {
1683 switch (this.getDate()) {
1700 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1703 * An array of textual month names.
1704 * Override these values for international dates, for example...
1705 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1724 * An array of textual day names.
1725 * Override these values for international dates, for example...
1726 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1742 Date.monthNumbers = {
1757 * Creates and returns a new Date instance with the exact same date value as the called instance.
1758 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1759 * variable will also be changed. When the intention is to create a new variable that will not
1760 * modify the original instance, you should create a clone.
1762 * Example of correctly cloning a date:
1765 var orig = new Date('10/1/2006');
1768 document.write(orig); //returns 'Thu Oct 05 2006'!
1771 var orig = new Date('10/1/2006');
1772 var copy = orig.clone();
1774 document.write(orig); //returns 'Thu Oct 01 2006'
1776 * @return {Date} The new Date instance
1778 Date.prototype.clone = function() {
1779 return new Date(this.getTime());
1783 * Clears any time information from this date
1784 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1785 @return {Date} this or the clone
1787 Date.prototype.clearTime = function(clone){
1789 return this.clone().clearTime();
1794 this.setMilliseconds(0);
1799 // safari setMonth is broken -- check that this is only donw once...
1800 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1801 Date.brokenSetMonth = Date.prototype.setMonth;
1802 Date.prototype.setMonth = function(num){
1804 var n = Math.ceil(-num);
1805 var back_year = Math.ceil(n/12);
1806 var month = (n % 12) ? 12 - n % 12 : 0 ;
1807 this.setFullYear(this.getFullYear() - back_year);
1808 return Date.brokenSetMonth.call(this, month);
1810 return Date.brokenSetMonth.apply(this, arguments);
1815 /** Date interval constant
1819 /** Date interval constant
1823 /** Date interval constant
1827 /** Date interval constant
1831 /** Date interval constant
1835 /** Date interval constant
1839 /** Date interval constant
1845 * Provides a convenient method of performing basic date arithmetic. This method
1846 * does not modify the Date instance being called - it creates and returns
1847 * a new Date instance containing the resulting date value.
1852 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1853 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1855 //Negative values will subtract correctly:
1856 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1857 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1859 //You can even chain several calls together in one line!
1860 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1861 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1864 * @param {String} interval A valid date interval enum value
1865 * @param {Number} value The amount to add to the current date
1866 * @return {Date} The new Date instance
1868 Date.prototype.add = function(interval, value){
1869 var d = this.clone();
1870 if (!interval || value === 0) { return d; }
1871 switch(interval.toLowerCase()){
1873 d.setMilliseconds(this.getMilliseconds() + value);
1876 d.setSeconds(this.getSeconds() + value);
1879 d.setMinutes(this.getMinutes() + value);
1882 d.setHours(this.getHours() + value);
1885 d.setDate(this.getDate() + value);
1888 var day = this.getDate();
1890 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1893 d.setMonth(this.getMonth() + value);
1896 d.setFullYear(this.getFullYear() + value);
1902 * @class Roo.lib.Dom
1906 * Dom utils (from YIU afaik)
1912 * Get the view width
1913 * @param {Boolean} full True will get the full document, otherwise it's the view width
1914 * @return {Number} The width
1917 getViewWidth : function(full) {
1918 return full ? this.getDocumentWidth() : this.getViewportWidth();
1921 * Get the view height
1922 * @param {Boolean} full True will get the full document, otherwise it's the view height
1923 * @return {Number} The height
1925 getViewHeight : function(full) {
1926 return full ? this.getDocumentHeight() : this.getViewportHeight();
1929 * Get the Full Document height
1930 * @return {Number} The height
1932 getDocumentHeight: function() {
1933 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1934 return Math.max(scrollHeight, this.getViewportHeight());
1937 * Get the Full Document width
1938 * @return {Number} The width
1940 getDocumentWidth: function() {
1941 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1942 return Math.max(scrollWidth, this.getViewportWidth());
1945 * Get the Window Viewport height
1946 * @return {Number} The height
1948 getViewportHeight: function() {
1949 var height = self.innerHeight;
1950 var mode = document.compatMode;
1952 if ((mode || Roo.isIE) && !Roo.isOpera) {
1953 height = (mode == "CSS1Compat") ?
1954 document.documentElement.clientHeight :
1955 document.body.clientHeight;
1961 * Get the Window Viewport width
1962 * @return {Number} The width
1964 getViewportWidth: function() {
1965 var width = self.innerWidth;
1966 var mode = document.compatMode;
1968 if (mode || Roo.isIE) {
1969 width = (mode == "CSS1Compat") ?
1970 document.documentElement.clientWidth :
1971 document.body.clientWidth;
1976 isAncestor : function(p, c) {
1983 if (p.contains && !Roo.isSafari) {
1984 return p.contains(c);
1985 } else if (p.compareDocumentPosition) {
1986 return !!(p.compareDocumentPosition(c) & 16);
1988 var parent = c.parentNode;
1993 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1996 parent = parent.parentNode;
2002 getRegion : function(el) {
2003 return Roo.lib.Region.getRegion(el);
2006 getY : function(el) {
2007 return this.getXY(el)[1];
2010 getX : function(el) {
2011 return this.getXY(el)[0];
2014 getXY : function(el) {
2015 var p, pe, b, scroll, bd = document.body;
2016 el = Roo.getDom(el);
2017 var fly = Roo.lib.AnimBase.fly;
2018 if (el.getBoundingClientRect) {
2019 b = el.getBoundingClientRect();
2020 scroll = fly(document).getScroll();
2021 return [b.left + scroll.left, b.top + scroll.top];
2027 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2034 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2041 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2042 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2049 if (p != el && pe.getStyle('overflow') != 'visible') {
2057 if (Roo.isSafari && hasAbsolute) {
2062 if (Roo.isGecko && !hasAbsolute) {
2064 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2065 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2069 while (p && p != bd) {
2070 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2082 setXY : function(el, xy) {
2083 el = Roo.fly(el, '_setXY');
2085 var pts = el.translatePoints(xy);
2086 if (xy[0] !== false) {
2087 el.dom.style.left = pts.left + "px";
2089 if (xy[1] !== false) {
2090 el.dom.style.top = pts.top + "px";
2094 setX : function(el, x) {
2095 this.setXY(el, [x, false]);
2098 setY : function(el, y) {
2099 this.setXY(el, [false, y]);
2103 * Portions of this file are based on pieces of Yahoo User Interface Library
2104 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2105 * YUI licensed under the BSD License:
2106 * http://developer.yahoo.net/yui/license.txt
2107 * <script type="text/javascript">
2111 Roo.lib.Event = function() {
2112 var loadComplete = false;
2114 var unloadListeners = [];
2116 var onAvailStack = [];
2118 var lastError = null;
2131 startInterval: function() {
2132 if (!this._interval) {
2134 var callback = function() {
2135 self._tryPreloadAttach();
2137 this._interval = setInterval(callback, this.POLL_INTERVAL);
2142 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2143 onAvailStack.push({ id: p_id,
2146 override: p_override,
2147 checkReady: false });
2149 retryCount = this.POLL_RETRYS;
2150 this.startInterval();
2154 addListener: function(el, eventName, fn) {
2155 el = Roo.getDom(el);
2160 if ("unload" == eventName) {
2161 unloadListeners[unloadListeners.length] =
2162 [el, eventName, fn];
2166 var wrappedFn = function(e) {
2167 return fn(Roo.lib.Event.getEvent(e));
2170 var li = [el, eventName, fn, wrappedFn];
2172 var index = listeners.length;
2173 listeners[index] = li;
2175 this.doAdd(el, eventName, wrappedFn, false);
2181 removeListener: function(el, eventName, fn) {
2184 el = Roo.getDom(el);
2187 return this.purgeElement(el, false, eventName);
2191 if ("unload" == eventName) {
2193 for (i = 0,len = unloadListeners.length; i < len; i++) {
2194 var li = unloadListeners[i];
2197 li[1] == eventName &&
2199 unloadListeners.splice(i, 1);
2207 var cacheItem = null;
2210 var index = arguments[3];
2212 if ("undefined" == typeof index) {
2213 index = this._getCacheIndex(el, eventName, fn);
2217 cacheItem = listeners[index];
2220 if (!el || !cacheItem) {
2224 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2226 delete listeners[index][this.WFN];
2227 delete listeners[index][this.FN];
2228 listeners.splice(index, 1);
2235 getTarget: function(ev, resolveTextNode) {
2236 ev = ev.browserEvent || ev;
2237 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2238 var t = ev.target || ev.srcElement;
2239 return this.resolveTextNode(t);
2243 resolveTextNode: function(node) {
2244 if (Roo.isSafari && node && 3 == node.nodeType) {
2245 return node.parentNode;
2252 getPageX: function(ev) {
2253 ev = ev.browserEvent || ev;
2254 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2256 if (!x && 0 !== x) {
2257 x = ev.clientX || 0;
2260 x += this.getScroll()[1];
2268 getPageY: function(ev) {
2269 ev = ev.browserEvent || ev;
2270 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2272 if (!y && 0 !== y) {
2273 y = ev.clientY || 0;
2276 y += this.getScroll()[0];
2285 getXY: function(ev) {
2286 ev = ev.browserEvent || ev;
2287 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2288 return [this.getPageX(ev), this.getPageY(ev)];
2292 getRelatedTarget: function(ev) {
2293 ev = ev.browserEvent || ev;
2294 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2295 var t = ev.relatedTarget;
2297 if (ev.type == "mouseout") {
2299 } else if (ev.type == "mouseover") {
2304 return this.resolveTextNode(t);
2308 getTime: function(ev) {
2309 ev = ev.browserEvent || ev;
2310 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2312 var t = new Date().getTime();
2316 this.lastError = ex;
2325 stopEvent: function(ev) {
2326 this.stopPropagation(ev);
2327 this.preventDefault(ev);
2331 stopPropagation: function(ev) {
2332 ev = ev.browserEvent || ev;
2333 if (ev.stopPropagation) {
2334 ev.stopPropagation();
2336 ev.cancelBubble = true;
2341 preventDefault: function(ev) {
2342 ev = ev.browserEvent || ev;
2343 if(ev.preventDefault) {
2344 ev.preventDefault();
2346 ev.returnValue = false;
2351 getEvent: function(e) {
2352 var ev = e || window.event;
2354 var c = this.getEvent.caller;
2356 ev = c.arguments[0];
2357 if (ev && Event == ev.constructor) {
2367 getCharCode: function(ev) {
2368 ev = ev.browserEvent || ev;
2369 return ev.charCode || ev.keyCode || 0;
2373 _getCacheIndex: function(el, eventName, fn) {
2374 for (var i = 0,len = listeners.length; i < len; ++i) {
2375 var li = listeners[i];
2377 li[this.FN] == fn &&
2378 li[this.EL] == el &&
2379 li[this.TYPE] == eventName) {
2391 getEl: function(id) {
2392 return document.getElementById(id);
2396 clearCache: function() {
2400 _load: function(e) {
2401 loadComplete = true;
2402 var EU = Roo.lib.Event;
2406 EU.doRemove(window, "load", EU._load);
2411 _tryPreloadAttach: function() {
2420 var tryAgain = !loadComplete;
2422 tryAgain = (retryCount > 0);
2427 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2428 var item = onAvailStack[i];
2430 var el = this.getEl(item.id);
2433 if (!item.checkReady ||
2436 (document && document.body)) {
2439 if (item.override) {
2440 if (item.override === true) {
2443 scope = item.override;
2446 item.fn.call(scope, item.obj);
2447 onAvailStack[i] = null;
2450 notAvail.push(item);
2455 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2459 this.startInterval();
2461 clearInterval(this._interval);
2462 this._interval = null;
2465 this.locked = false;
2472 purgeElement: function(el, recurse, eventName) {
2473 var elListeners = this.getListeners(el, eventName);
2475 for (var i = 0,len = elListeners.length; i < len; ++i) {
2476 var l = elListeners[i];
2477 this.removeListener(el, l.type, l.fn);
2481 if (recurse && el && el.childNodes) {
2482 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2483 this.purgeElement(el.childNodes[i], recurse, eventName);
2489 getListeners: function(el, eventName) {
2490 var results = [], searchLists;
2492 searchLists = [listeners, unloadListeners];
2493 } else if (eventName == "unload") {
2494 searchLists = [unloadListeners];
2496 searchLists = [listeners];
2499 for (var j = 0; j < searchLists.length; ++j) {
2500 var searchList = searchLists[j];
2501 if (searchList && searchList.length > 0) {
2502 for (var i = 0,len = searchList.length; i < len; ++i) {
2503 var l = searchList[i];
2504 if (l && l[this.EL] === el &&
2505 (!eventName || eventName === l[this.TYPE])) {
2510 adjust: l[this.ADJ_SCOPE],
2518 return (results.length) ? results : null;
2522 _unload: function(e) {
2524 var EU = Roo.lib.Event, i, j, l, len, index;
2526 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2527 l = unloadListeners[i];
2530 if (l[EU.ADJ_SCOPE]) {
2531 if (l[EU.ADJ_SCOPE] === true) {
2534 scope = l[EU.ADJ_SCOPE];
2537 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2538 unloadListeners[i] = null;
2544 unloadListeners = null;
2546 if (listeners && listeners.length > 0) {
2547 j = listeners.length;
2550 l = listeners[index];
2552 EU.removeListener(l[EU.EL], l[EU.TYPE],
2562 EU.doRemove(window, "unload", EU._unload);
2567 getScroll: function() {
2568 var dd = document.documentElement, db = document.body;
2569 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2570 return [dd.scrollTop, dd.scrollLeft];
2572 return [db.scrollTop, db.scrollLeft];
2579 doAdd: function () {
2580 if (window.addEventListener) {
2581 return function(el, eventName, fn, capture) {
2582 el.addEventListener(eventName, fn, (capture));
2584 } else if (window.attachEvent) {
2585 return function(el, eventName, fn, capture) {
2586 el.attachEvent("on" + eventName, fn);
2595 doRemove: function() {
2596 if (window.removeEventListener) {
2597 return function (el, eventName, fn, capture) {
2598 el.removeEventListener(eventName, fn, (capture));
2600 } else if (window.detachEvent) {
2601 return function (el, eventName, fn) {
2602 el.detachEvent("on" + eventName, fn);
2614 var E = Roo.lib.Event;
2615 E.on = E.addListener;
2616 E.un = E.removeListener;
2618 if (document && document.body) {
2621 E.doAdd(window, "load", E._load);
2623 E.doAdd(window, "unload", E._unload);
2624 E._tryPreloadAttach();
2631 * @class Roo.lib.Ajax
2633 * provide a simple Ajax request utility functions
2635 * Portions of this file are based on pieces of Yahoo User Interface Library
2636 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2637 * YUI licensed under the BSD License:
2638 * http://developer.yahoo.net/yui/license.txt
2639 * <script type="text/javascript">
2647 request : function(method, uri, cb, data, options) {
2649 var hs = options.headers;
2652 if(hs.hasOwnProperty(h)){
2653 this.initHeader(h, hs[h], false);
2657 if(options.xmlData){
2658 this.initHeader('Content-Type', 'text/xml', false);
2660 data = options.xmlData;
2664 return this.asyncRequest(method, uri, cb, data);
2670 * @param {DomForm} form element
2671 * @return {String} urlencode form output.
2673 serializeForm : function(form) {
2674 if(typeof form == 'string') {
2675 form = (document.getElementById(form) || document.forms[form]);
2678 var el, name, val, disabled, data = '', hasSubmit = false;
2679 for (var i = 0; i < form.elements.length; i++) {
2680 el = form.elements[i];
2681 disabled = form.elements[i].disabled;
2682 name = form.elements[i].name;
2683 val = form.elements[i].value;
2685 if (!disabled && name){
2689 case 'select-multiple':
2690 for (var j = 0; j < el.options.length; j++) {
2691 if (el.options[j].selected) {
2693 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2696 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2704 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2717 if(hasSubmit == false) {
2718 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2723 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2728 data = data.substr(0, data.length - 1);
2736 useDefaultHeader:true,
2738 defaultPostHeader:'application/x-www-form-urlencoded',
2740 useDefaultXhrHeader:true,
2742 defaultXhrHeader:'XMLHttpRequest',
2744 hasDefaultHeaders:true,
2756 setProgId:function(id)
2758 this.activeX.unshift(id);
2761 setDefaultPostHeader:function(b)
2763 this.useDefaultHeader = b;
2766 setDefaultXhrHeader:function(b)
2768 this.useDefaultXhrHeader = b;
2771 setPollingInterval:function(i)
2773 if (typeof i == 'number' && isFinite(i)) {
2774 this.pollInterval = i;
2778 createXhrObject:function(transactionId)
2784 http = new XMLHttpRequest();
2786 obj = { conn:http, tId:transactionId };
2790 for (var i = 0; i < this.activeX.length; ++i) {
2794 http = new ActiveXObject(this.activeX[i]);
2796 obj = { conn:http, tId:transactionId };
2809 getConnectionObject:function()
2812 var tId = this.transactionId;
2816 o = this.createXhrObject(tId);
2818 this.transactionId++;
2829 asyncRequest:function(method, uri, callback, postData)
2831 var o = this.getConnectionObject();
2837 o.conn.open(method, uri, true);
2839 if (this.useDefaultXhrHeader) {
2840 if (!this.defaultHeaders['X-Requested-With']) {
2841 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2845 if(postData && this.useDefaultHeader){
2846 this.initHeader('Content-Type', this.defaultPostHeader);
2849 if (this.hasDefaultHeaders || this.hasHeaders) {
2853 this.handleReadyState(o, callback);
2854 o.conn.send(postData || null);
2860 handleReadyState:function(o, callback)
2864 if (callback && callback.timeout) {
2866 this.timeout[o.tId] = window.setTimeout(function() {
2867 oConn.abort(o, callback, true);
2868 }, callback.timeout);
2871 this.poll[o.tId] = window.setInterval(
2873 if (o.conn && o.conn.readyState == 4) {
2874 window.clearInterval(oConn.poll[o.tId]);
2875 delete oConn.poll[o.tId];
2877 if(callback && callback.timeout) {
2878 window.clearTimeout(oConn.timeout[o.tId]);
2879 delete oConn.timeout[o.tId];
2882 oConn.handleTransactionResponse(o, callback);
2885 , this.pollInterval);
2888 handleTransactionResponse:function(o, callback, isAbort)
2892 this.releaseObject(o);
2896 var httpStatus, responseObject;
2900 if (o.conn.status !== undefined && o.conn.status != 0) {
2901 httpStatus = o.conn.status;
2913 if (httpStatus >= 200 && httpStatus < 300) {
2914 responseObject = this.createResponseObject(o, callback.argument);
2915 if (callback.success) {
2916 if (!callback.scope) {
2917 callback.success(responseObject);
2922 callback.success.apply(callback.scope, [responseObject]);
2927 switch (httpStatus) {
2935 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2936 if (callback.failure) {
2937 if (!callback.scope) {
2938 callback.failure(responseObject);
2941 callback.failure.apply(callback.scope, [responseObject]);
2946 responseObject = this.createResponseObject(o, callback.argument);
2947 if (callback.failure) {
2948 if (!callback.scope) {
2949 callback.failure(responseObject);
2952 callback.failure.apply(callback.scope, [responseObject]);
2958 this.releaseObject(o);
2959 responseObject = null;
2962 createResponseObject:function(o, callbackArg)
2969 var headerStr = o.conn.getAllResponseHeaders();
2970 var header = headerStr.split('\n');
2971 for (var i = 0; i < header.length; i++) {
2972 var delimitPos = header[i].indexOf(':');
2973 if (delimitPos != -1) {
2974 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2982 obj.status = o.conn.status;
2983 obj.statusText = o.conn.statusText;
2984 obj.getResponseHeader = headerObj;
2985 obj.getAllResponseHeaders = headerStr;
2986 obj.responseText = o.conn.responseText;
2987 obj.responseXML = o.conn.responseXML;
2989 if (typeof callbackArg !== undefined) {
2990 obj.argument = callbackArg;
2996 createExceptionObject:function(tId, callbackArg, isAbort)
2999 var COMM_ERROR = 'communication failure';
3000 var ABORT_CODE = -1;
3001 var ABORT_ERROR = 'transaction aborted';
3007 obj.status = ABORT_CODE;
3008 obj.statusText = ABORT_ERROR;
3011 obj.status = COMM_CODE;
3012 obj.statusText = COMM_ERROR;
3016 obj.argument = callbackArg;
3022 initHeader:function(label, value, isDefault)
3024 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3026 if (headerObj[label] === undefined) {
3027 headerObj[label] = value;
3032 headerObj[label] = value + "," + headerObj[label];
3036 this.hasDefaultHeaders = true;
3039 this.hasHeaders = true;
3044 setHeader:function(o)
3046 if (this.hasDefaultHeaders) {
3047 for (var prop in this.defaultHeaders) {
3048 if (this.defaultHeaders.hasOwnProperty(prop)) {
3049 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3054 if (this.hasHeaders) {
3055 for (var prop in this.headers) {
3056 if (this.headers.hasOwnProperty(prop)) {
3057 o.conn.setRequestHeader(prop, this.headers[prop]);
3061 this.hasHeaders = false;
3065 resetDefaultHeaders:function() {
3066 delete this.defaultHeaders;
3067 this.defaultHeaders = {};
3068 this.hasDefaultHeaders = false;
3071 abort:function(o, callback, isTimeout)
3073 if(this.isCallInProgress(o)) {
3075 window.clearInterval(this.poll[o.tId]);
3076 delete this.poll[o.tId];
3078 delete this.timeout[o.tId];
3081 this.handleTransactionResponse(o, callback, true);
3091 isCallInProgress:function(o)
3094 return o.conn.readyState != 4 && o.conn.readyState != 0;
3103 releaseObject:function(o)
3112 'MSXML2.XMLHTTP.3.0',
3120 * Portions of this file are based on pieces of Yahoo User Interface Library
3121 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3122 * YUI licensed under the BSD License:
3123 * http://developer.yahoo.net/yui/license.txt
3124 * <script type="text/javascript">
3128 Roo.lib.Region = function(t, r, b, l) {
3138 Roo.lib.Region.prototype = {
3139 contains : function(region) {
3140 return ( region.left >= this.left &&
3141 region.right <= this.right &&
3142 region.top >= this.top &&
3143 region.bottom <= this.bottom );
3147 getArea : function() {
3148 return ( (this.bottom - this.top) * (this.right - this.left) );
3151 intersect : function(region) {
3152 var t = Math.max(this.top, region.top);
3153 var r = Math.min(this.right, region.right);
3154 var b = Math.min(this.bottom, region.bottom);
3155 var l = Math.max(this.left, region.left);
3157 if (b >= t && r >= l) {
3158 return new Roo.lib.Region(t, r, b, l);
3163 union : function(region) {
3164 var t = Math.min(this.top, region.top);
3165 var r = Math.max(this.right, region.right);
3166 var b = Math.max(this.bottom, region.bottom);
3167 var l = Math.min(this.left, region.left);
3169 return new Roo.lib.Region(t, r, b, l);
3172 adjust : function(t, l, b, r) {
3181 Roo.lib.Region.getRegion = function(el) {
3182 var p = Roo.lib.Dom.getXY(el);
3185 var r = p[0] + el.offsetWidth;
3186 var b = p[1] + el.offsetHeight;
3189 return new Roo.lib.Region(t, r, b, l);
3192 * Portions of this file are based on pieces of Yahoo User Interface Library
3193 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3194 * YUI licensed under the BSD License:
3195 * http://developer.yahoo.net/yui/license.txt
3196 * <script type="text/javascript">
3199 //@@dep Roo.lib.Region
3202 Roo.lib.Point = function(x, y) {
3203 if (x instanceof Array) {
3207 this.x = this.right = this.left = this[0] = x;
3208 this.y = this.top = this.bottom = this[1] = y;
3211 Roo.lib.Point.prototype = new Roo.lib.Region();
3213 * Portions of this file are based on pieces of Yahoo User Interface Library
3214 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3215 * YUI licensed under the BSD License:
3216 * http://developer.yahoo.net/yui/license.txt
3217 * <script type="text/javascript">
3224 scroll : function(el, args, duration, easing, cb, scope) {
3225 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3228 motion : function(el, args, duration, easing, cb, scope) {
3229 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3232 color : function(el, args, duration, easing, cb, scope) {
3233 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3236 run : function(el, args, duration, easing, cb, scope, type) {
3237 type = type || Roo.lib.AnimBase;
3238 if (typeof easing == "string") {
3239 easing = Roo.lib.Easing[easing];
3241 var anim = new type(el, args, duration, easing);
3242 anim.animateX(function() {
3243 Roo.callback(cb, scope);
3249 * Portions of this file are based on pieces of Yahoo User Interface Library
3250 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3251 * YUI licensed under the BSD License:
3252 * http://developer.yahoo.net/yui/license.txt
3253 * <script type="text/javascript">
3261 if (!libFlyweight) {
3262 libFlyweight = new Roo.Element.Flyweight();
3264 libFlyweight.dom = el;
3265 return libFlyweight;
3268 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3272 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3274 this.init(el, attributes, duration, method);
3278 Roo.lib.AnimBase.fly = fly;
3282 Roo.lib.AnimBase.prototype = {
3284 toString: function() {
3285 var el = this.getEl();
3286 var id = el.id || el.tagName;
3287 return ("Anim " + id);
3291 noNegatives: /width|height|opacity|padding/i,
3292 offsetAttribute: /^((width|height)|(top|left))$/,
3293 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3294 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3298 doMethod: function(attr, start, end) {
3299 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3303 setAttribute: function(attr, val, unit) {
3304 if (this.patterns.noNegatives.test(attr)) {
3305 val = (val > 0) ? val : 0;
3308 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3312 getAttribute: function(attr) {
3313 var el = this.getEl();
3314 var val = fly(el).getStyle(attr);
3316 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3317 return parseFloat(val);
3320 var a = this.patterns.offsetAttribute.exec(attr) || [];
3321 var pos = !!( a[3] );
3322 var box = !!( a[2] );
3325 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3326 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3335 getDefaultUnit: function(attr) {
3336 if (this.patterns.defaultUnit.test(attr)) {
3343 animateX : function(callback, scope) {
3344 var f = function() {
3345 this.onComplete.removeListener(f);
3346 if (typeof callback == "function") {
3347 callback.call(scope || this, this);
3350 this.onComplete.addListener(f, this);
3355 setRuntimeAttribute: function(attr) {
3358 var attributes = this.attributes;
3360 this.runtimeAttributes[attr] = {};
3362 var isset = function(prop) {
3363 return (typeof prop !== 'undefined');
3366 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3370 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3373 if (isset(attributes[attr]['to'])) {
3374 end = attributes[attr]['to'];
3375 } else if (isset(attributes[attr]['by'])) {
3376 if (start.constructor == Array) {
3378 for (var i = 0, len = start.length; i < len; ++i) {
3379 end[i] = start[i] + attributes[attr]['by'][i];
3382 end = start + attributes[attr]['by'];
3386 this.runtimeAttributes[attr].start = start;
3387 this.runtimeAttributes[attr].end = end;
3390 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3394 init: function(el, attributes, duration, method) {
3396 var isAnimated = false;
3399 var startTime = null;
3402 var actualFrames = 0;
3405 el = Roo.getDom(el);
3408 this.attributes = attributes || {};
3411 this.duration = duration || 1;
3414 this.method = method || Roo.lib.Easing.easeNone;
3417 this.useSeconds = true;
3420 this.currentFrame = 0;
3423 this.totalFrames = Roo.lib.AnimMgr.fps;
3426 this.getEl = function() {
3431 this.isAnimated = function() {
3436 this.getStartTime = function() {
3440 this.runtimeAttributes = {};
3443 this.animate = function() {
3444 if (this.isAnimated()) {
3448 this.currentFrame = 0;
3450 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3452 Roo.lib.AnimMgr.registerElement(this);
3456 this.stop = function(finish) {
3458 this.currentFrame = this.totalFrames;
3459 this._onTween.fire();
3461 Roo.lib.AnimMgr.stop(this);
3464 var onStart = function() {
3465 this.onStart.fire();
3467 this.runtimeAttributes = {};
3468 for (var attr in this.attributes) {
3469 this.setRuntimeAttribute(attr);
3474 startTime = new Date();
3478 var onTween = function() {
3480 duration: new Date() - this.getStartTime(),
3481 currentFrame: this.currentFrame
3484 data.toString = function() {
3486 'duration: ' + data.duration +
3487 ', currentFrame: ' + data.currentFrame
3491 this.onTween.fire(data);
3493 var runtimeAttributes = this.runtimeAttributes;
3495 for (var attr in runtimeAttributes) {
3496 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3502 var onComplete = function() {
3503 var actual_duration = (new Date() - startTime) / 1000 ;
3506 duration: actual_duration,
3507 frames: actualFrames,
3508 fps: actualFrames / actual_duration
3511 data.toString = function() {
3513 'duration: ' + data.duration +
3514 ', frames: ' + data.frames +
3515 ', fps: ' + data.fps
3521 this.onComplete.fire(data);
3525 this._onStart = new Roo.util.Event(this);
3526 this.onStart = new Roo.util.Event(this);
3527 this.onTween = new Roo.util.Event(this);
3528 this._onTween = new Roo.util.Event(this);
3529 this.onComplete = new Roo.util.Event(this);
3530 this._onComplete = new Roo.util.Event(this);
3531 this._onStart.addListener(onStart);
3532 this._onTween.addListener(onTween);
3533 this._onComplete.addListener(onComplete);
3538 * Portions of this file are based on pieces of Yahoo User Interface Library
3539 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3540 * YUI licensed under the BSD License:
3541 * http://developer.yahoo.net/yui/license.txt
3542 * <script type="text/javascript">
3546 Roo.lib.AnimMgr = new function() {
3563 this.registerElement = function(tween) {
3564 queue[queue.length] = tween;
3566 tween._onStart.fire();
3571 this.unRegister = function(tween, index) {
3572 tween._onComplete.fire();
3573 index = index || getIndex(tween);
3575 queue.splice(index, 1);
3579 if (tweenCount <= 0) {
3585 this.start = function() {
3586 if (thread === null) {
3587 thread = setInterval(this.run, this.delay);
3592 this.stop = function(tween) {
3594 clearInterval(thread);
3596 for (var i = 0, len = queue.length; i < len; ++i) {
3597 if (queue[0].isAnimated()) {
3598 this.unRegister(queue[0], 0);
3607 this.unRegister(tween);
3612 this.run = function() {
3613 for (var i = 0, len = queue.length; i < len; ++i) {
3614 var tween = queue[i];
3615 if (!tween || !tween.isAnimated()) {
3619 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3621 tween.currentFrame += 1;
3623 if (tween.useSeconds) {
3624 correctFrame(tween);
3626 tween._onTween.fire();
3629 Roo.lib.AnimMgr.stop(tween, i);
3634 var getIndex = function(anim) {
3635 for (var i = 0, len = queue.length; i < len; ++i) {
3636 if (queue[i] == anim) {
3644 var correctFrame = function(tween) {
3645 var frames = tween.totalFrames;
3646 var frame = tween.currentFrame;
3647 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3648 var elapsed = (new Date() - tween.getStartTime());
3651 if (elapsed < tween.duration * 1000) {
3652 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3654 tweak = frames - (frame + 1);
3656 if (tweak > 0 && isFinite(tweak)) {
3657 if (tween.currentFrame + tweak >= frames) {
3658 tweak = frames - (frame + 1);
3661 tween.currentFrame += tweak;
3667 * Portions of this file are based on pieces of Yahoo User Interface Library
3668 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3669 * YUI licensed under the BSD License:
3670 * http://developer.yahoo.net/yui/license.txt
3671 * <script type="text/javascript">
3674 Roo.lib.Bezier = new function() {
3676 this.getPosition = function(points, t) {
3677 var n = points.length;
3680 for (var i = 0; i < n; ++i) {
3681 tmp[i] = [points[i][0], points[i][1]];
3684 for (var j = 1; j < n; ++j) {
3685 for (i = 0; i < n - j; ++i) {
3686 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3687 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3691 return [ tmp[0][0], tmp[0][1] ];
3697 * @class Roo.lib.Color
3699 * An abstract Color implementation. Concrete Color implementations should use
3700 * an instance of this function as their prototype, and implement the getRGB and
3701 * getHSL functions. getRGB should return an object representing the RGB
3702 * components of this Color, with the red, green, and blue components in the
3703 * range [0,255] and the alpha component in the range [0,100]. getHSL should
3704 * return an object representing the HSL components of this Color, with the hue
3705 * component in the range [0,360), the saturation and lightness components in
3706 * the range [0,100], and the alpha component in the range [0,1].
3711 * Functions for Color handling and processing.
3713 * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3715 * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3716 * rights to this program, with the intention of it becoming part of the public
3717 * domain. Because this program is released into the public domain, it comes with
3718 * no warranty either expressed or implied, to the extent permitted by law.
3720 * For more free and public domain JavaScript code by the same author, visit:
3721 * http://www.safalra.com/web-design/javascript/
3724 Roo.lib.Color = function() { }
3727 Roo.apply(Roo.lib.Color.prototype, {
3735 * @return {Object} an object representing the RGBA components of this Color. The red,
3736 * green, and blue components are converted to integers in the range [0,255].
3737 * The alpha is a value in the range [0,1].
3739 getIntegerRGB : function(){
3741 // get the RGB components of this Color
3742 var rgb = this.getRGB();
3744 // return the integer components
3746 'r' : Math.round(rgb.r),
3747 'g' : Math.round(rgb.g),
3748 'b' : Math.round(rgb.b),
3756 * @return {Object} an object representing the RGBA components of this Color. The red,
3757 * green, and blue components are converted to numbers in the range [0,100].
3758 * The alpha is a value in the range [0,1].
3760 getPercentageRGB : function(){
3762 // get the RGB components of this Color
3763 var rgb = this.getRGB();
3765 // return the percentage components
3767 'r' : 100 * rgb.r / 255,
3768 'g' : 100 * rgb.g / 255,
3769 'b' : 100 * rgb.b / 255,
3776 * getCSSHexadecimalRGB
3777 * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3778 * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3779 * are two-digit hexadecimal numbers.
3781 getCSSHexadecimalRGB : function()
3784 // get the integer RGB components
3785 var rgb = this.getIntegerRGB();
3787 // determine the hexadecimal equivalents
3788 var r16 = rgb.r.toString(16);
3789 var g16 = rgb.g.toString(16);
3790 var b16 = rgb.b.toString(16);
3792 // return the CSS RGB Color value
3794 + (r16.length == 2 ? r16 : '0' + r16)
3795 + (g16.length == 2 ? g16 : '0' + g16)
3796 + (b16.length == 2 ? b16 : '0' + b16);
3802 * @return {String} a string representing this Color as a CSS integer RGB Color
3803 * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3804 * are integers in the range [0,255].
3806 getCSSIntegerRGB : function(){
3808 // get the integer RGB components
3809 var rgb = this.getIntegerRGB();
3811 // return the CSS RGB Color value
3812 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3818 * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3819 * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3820 * b are integers in the range [0,255] and a is in the range [0,1].
3822 getCSSIntegerRGBA : function(){
3824 // get the integer RGB components
3825 var rgb = this.getIntegerRGB();
3827 // return the CSS integer RGBA Color value
3828 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3833 * getCSSPercentageRGB
3834 * @return {String} a string representing this Color as a CSS percentage RGB Color
3835 * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3836 * b are in the range [0,100].
3838 getCSSPercentageRGB : function(){
3840 // get the percentage RGB components
3841 var rgb = this.getPercentageRGB();
3843 // return the CSS RGB Color value
3844 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3849 * getCSSPercentageRGBA
3850 * @return {String} a string representing this Color as a CSS percentage RGBA Color
3851 * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3852 * and b are in the range [0,100] and a is in the range [0,1].
3854 getCSSPercentageRGBA : function(){
3856 // get the percentage RGB components
3857 var rgb = this.getPercentageRGB();
3859 // return the CSS percentage RGBA Color value
3860 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3866 * @return {String} a string representing this Color as a CSS HSL Color value - that
3867 * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3868 * s and l are in the range [0,100].
3870 getCSSHSL : function(){
3872 // get the HSL components
3873 var hsl = this.getHSL();
3875 // return the CSS HSL Color value
3876 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3882 * @return {String} a string representing this Color as a CSS HSLA Color value - that
3883 * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3884 * s and l are in the range [0,100], and a is in the range [0,1].
3886 getCSSHSLA : function(){
3888 // get the HSL components
3889 var hsl = this.getHSL();
3891 // return the CSS HSL Color value
3892 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3897 * Sets the Color of the specified node to this Color. This functions sets
3898 * the CSS 'color' property for the node. The parameter is:
3900 * @param {DomElement} node - the node whose Color should be set
3902 setNodeColor : function(node){
3904 // set the Color of the node
3905 node.style.color = this.getCSSHexadecimalRGB();
3910 * Sets the background Color of the specified node to this Color. This
3911 * functions sets the CSS 'background-color' property for the node. The
3914 * @param {DomElement} node - the node whose background Color should be set
3916 setNodeBackgroundColor : function(node){
3918 // set the background Color of the node
3919 node.style.backgroundColor = this.getCSSHexadecimalRGB();
3922 // convert between formats..
3925 var r = this.getIntegerRGB();
3926 return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3931 var hsl = this.getHSL();
3932 // return the CSS HSL Color value
3933 return new Roo.lib.HSLColor(hsl.h, hsl.s, hsl.l , hsl.a );
3939 var rgb = this.toRGB();
3940 var hsv = rgb.getHSV();
3941 // return the CSS HSL Color value
3942 return new Roo.lib.HSVColor(hsv.h, hsv.s, hsv.v , hsv.a );
3946 // modify v = 0 ... 1 (eg. 0.5)
3947 saturate : function(v)
3949 var rgb = this.toRGB();
3950 var hsv = rgb.getHSV();
3951 return new Roo.lib.HSVColor(hsv.h, hsv.s * v, hsv.v , hsv.a );
3959 * @return {Object} the RGB and alpha components of this Color as an object with r,
3960 * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3965 // return the RGB components
3977 * @return {Object} the HSV and alpha components of this Color as an object with h,
3978 * s, v, and a properties. h is in the range [0,360), s and v are in the range
3979 * [0,100], and a is in the range [0,1].
3984 // calculate the HSV components if necessary
3985 if (this.hsv == null) {
3986 this.calculateHSV();
3989 // return the HSV components
4001 * @return {Object} the HSL and alpha components of this Color as an object with h,
4002 * s, l, and a properties. h is in the range [0,360), s and l are in the range
4003 * [0,100], and a is in the range [0,1].
4005 getHSL : function(){
4008 // calculate the HSV components if necessary
4009 if (this.hsl == null) { this.calculateHSL(); }
4011 // return the HSL components
4026 * @class Roo.lib.RGBColor
4027 * @extends Roo.lib.Color
4028 * Creates a Color specified in the RGB Color space, with an optional alpha
4029 * component. The parameters are:
4033 * @param {Number} r - the red component, clipped to the range [0,255]
4034 * @param {Number} g - the green component, clipped to the range [0,255]
4035 * @param {Number} b - the blue component, clipped to the range [0,255]
4036 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4037 * optional and defaults to 1
4039 Roo.lib.RGBColor = function (r, g, b, a){
4041 // store the alpha component after clipping it if necessary
4042 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4044 // store the RGB components after clipping them if necessary
4047 'r' : Math.max(0, Math.min(255, r)),
4048 'g' : Math.max(0, Math.min(255, g)),
4049 'b' : Math.max(0, Math.min(255, b))
4052 // initialise the HSV and HSL components to null
4056 * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4057 * range [0,360). The parameters are:
4059 * maximum - the maximum of the RGB component values
4060 * range - the range of the RGB component values
4065 // this does an 'exteds'
4066 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4069 getHue : function(maximum, range)
4073 // check whether the range is zero
4076 // set the hue to zero (any hue is acceptable as the Color is grey)
4081 // determine which of the components has the highest value and set the hue
4084 // red has the highest value
4086 var hue = (rgb.g - rgb.b) / range * 60;
4087 if (hue < 0) { hue += 360; }
4090 // green has the highest value
4092 var hue = (rgb.b - rgb.r) / range * 60 + 120;
4095 // blue has the highest value
4097 var hue = (rgb.r - rgb.g) / range * 60 + 240;
4109 /* //private Calculates and stores the HSV components of this RGBColor so that they can
4110 * be returned be the getHSV function.
4112 calculateHSV : function(){
4114 // get the maximum and range of the RGB component values
4115 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4116 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4118 // store the HSV components
4121 'h' : this.getHue(maximum, range),
4122 's' : (maximum == 0 ? 0 : 100 * range / maximum),
4123 'v' : maximum / 2.55
4128 /* //private Calculates and stores the HSL components of this RGBColor so that they can
4129 * be returned be the getHSL function.
4131 calculateHSL : function(){
4133 // get the maximum and range of the RGB component values
4134 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4135 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4137 // determine the lightness in the range [0,1]
4138 var l = maximum / 255 - range / 510;
4140 // store the HSL components
4143 'h' : this.getHue(maximum, range),
4144 's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4153 * @class Roo.lib.HSVColor
4154 * @extends Roo.lib.Color
4155 * Creates a Color specified in the HSV Color space, with an optional alpha
4156 * component. The parameters are:
4159 * @param {Number} h - the hue component, wrapped to the range [0,360)
4160 * @param {Number} s - the saturation component, clipped to the range [0,100]
4161 * @param {Number} v - the value component, clipped to the range [0,100]
4162 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4163 * optional and defaults to 1
4165 Roo.lib.HSVColor = function (h, s, v, a){
4167 // store the alpha component after clipping it if necessary
4168 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4170 // store the HSV components after clipping or wrapping them if necessary
4173 'h' : (h % 360 + 360) % 360,
4174 's' : Math.max(0, Math.min(100, s)),
4175 'v' : Math.max(0, Math.min(100, v))
4178 // initialise the RGB and HSL components to null
4183 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4184 /* Calculates and stores the RGB components of this HSVColor so that they can
4185 * be returned be the getRGB function.
4187 calculateRGB: function ()
4190 // check whether the saturation is zero
4193 // set the Color to the appropriate shade of grey
4200 // set some temporary values
4201 var f = hsv.h / 60 - Math.floor(hsv.h / 60);
4202 var p = hsv.v * (1 - hsv.s / 100);
4203 var q = hsv.v * (1 - hsv.s / 100 * f);
4204 var t = hsv.v * (1 - hsv.s / 100 * (1 - f));
4206 // set the RGB Color components to their temporary values
4207 switch (Math.floor(hsv.h / 60)){
4208 case 0: var r = hsv.v; var g = t; var b = p; break;
4209 case 1: var r = q; var g = hsv.v; var b = p; break;
4210 case 2: var r = p; var g = hsv.v; var b = t; break;
4211 case 3: var r = p; var g = q; var b = hsv.v; break;
4212 case 4: var r = t; var g = p; var b = hsv.v; break;
4213 case 5: var r = hsv.v; var g = p; var b = q; break;
4218 // store the RGB components
4228 /* Calculates and stores the HSL components of this HSVColor so that they can
4229 * be returned be the getHSL function.
4231 calculateHSL : function (){
4234 // determine the lightness in the range [0,100]
4235 var l = (2 - hsv.s / 100) * hsv.v / 2;
4237 // store the HSL components
4241 's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4245 // correct a division-by-zero error
4246 if (isNaN(hsl.s)) { hsl.s = 0; }
4255 * @class Roo.lib.HSLColor
4256 * @extends Roo.lib.Color
4259 * Creates a Color specified in the HSL Color space, with an optional alpha
4260 * component. The parameters are:
4262 * @param {Number} h - the hue component, wrapped to the range [0,360)
4263 * @param {Number} s - the saturation component, clipped to the range [0,100]
4264 * @param {Number} l - the lightness component, clipped to the range [0,100]
4265 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4266 * optional and defaults to 1
4269 Roo.lib.HSLColor = function(h, s, l, a){
4271 // store the alpha component after clipping it if necessary
4272 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4274 // store the HSL components after clipping or wrapping them if necessary
4277 'h' : (h % 360 + 360) % 360,
4278 's' : Math.max(0, Math.min(100, s)),
4279 'l' : Math.max(0, Math.min(100, l))
4282 // initialise the RGB and HSV components to null
4285 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4287 /* Calculates and stores the RGB components of this HSLColor so that they can
4288 * be returned be the getRGB function.
4290 calculateRGB: function (){
4292 // check whether the saturation is zero
4293 if (this.hsl.s == 0){
4295 // store the RGB components representing the appropriate shade of grey
4298 'r' : this.hsl.l * 2.55,
4299 'g' : this.hsl.l * 2.55,
4300 'b' : this.hsl.l * 2.55
4305 // set some temporary values
4306 var p = this.hsl.l < 50
4307 ? this.hsl.l * (1 + hsl.s / 100)
4308 : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4309 var q = 2 * hsl.l - p;
4311 // initialise the RGB components
4314 'r' : (h + 120) / 60 % 6,
4316 'b' : (h + 240) / 60 % 6
4319 // loop over the RGB components
4320 for (var key in this.rgb){
4322 // ensure that the property is not inherited from the root object
4323 if (this.rgb.hasOwnProperty(key)){
4325 // set the component to its value in the range [0,100]
4326 if (this.rgb[key] < 1){
4327 this.rgb[key] = q + (p - q) * this.rgb[key];
4328 }else if (this.rgb[key] < 3){
4330 }else if (this.rgb[key] < 4){
4331 this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4336 // set the component to its value in the range [0,255]
4337 this.rgb[key] *= 2.55;
4347 /* Calculates and stores the HSV components of this HSLColor so that they can
4348 * be returned be the getHSL function.
4350 calculateHSV : function(){
4352 // set a temporary value
4353 var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4355 // store the HSV components
4359 's' : 200 * t / (this.hsl.l + t),
4360 'v' : t + this.hsl.l
4363 // correct a division-by-zero error
4364 if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4371 * Portions of this file are based on pieces of Yahoo User Interface Library
4372 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4373 * YUI licensed under the BSD License:
4374 * http://developer.yahoo.net/yui/license.txt
4375 * <script type="text/javascript">
4380 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4381 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4384 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4386 var fly = Roo.lib.AnimBase.fly;
4388 var superclass = Y.ColorAnim.superclass;
4389 var proto = Y.ColorAnim.prototype;
4391 proto.toString = function() {
4392 var el = this.getEl();
4393 var id = el.id || el.tagName;
4394 return ("ColorAnim " + id);
4397 proto.patterns.color = /color$/i;
4398 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4399 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4400 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4401 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4404 proto.parseColor = function(s) {
4405 if (s.length == 3) {
4409 var c = this.patterns.hex.exec(s);
4410 if (c && c.length == 4) {
4411 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4414 c = this.patterns.rgb.exec(s);
4415 if (c && c.length == 4) {
4416 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4419 c = this.patterns.hex3.exec(s);
4420 if (c && c.length == 4) {
4421 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4426 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4427 proto.getAttribute = function(attr) {
4428 var el = this.getEl();
4429 if (this.patterns.color.test(attr)) {
4430 var val = fly(el).getStyle(attr);
4432 if (this.patterns.transparent.test(val)) {
4433 var parent = el.parentNode;
4434 val = fly(parent).getStyle(attr);
4436 while (parent && this.patterns.transparent.test(val)) {
4437 parent = parent.parentNode;
4438 val = fly(parent).getStyle(attr);
4439 if (parent.tagName.toUpperCase() == 'HTML') {
4445 val = superclass.getAttribute.call(this, attr);
4450 proto.getAttribute = function(attr) {
4451 var el = this.getEl();
4452 if (this.patterns.color.test(attr)) {
4453 var val = fly(el).getStyle(attr);
4455 if (this.patterns.transparent.test(val)) {
4456 var parent = el.parentNode;
4457 val = fly(parent).getStyle(attr);
4459 while (parent && this.patterns.transparent.test(val)) {
4460 parent = parent.parentNode;
4461 val = fly(parent).getStyle(attr);
4462 if (parent.tagName.toUpperCase() == 'HTML') {
4468 val = superclass.getAttribute.call(this, attr);
4474 proto.doMethod = function(attr, start, end) {
4477 if (this.patterns.color.test(attr)) {
4479 for (var i = 0, len = start.length; i < len; ++i) {
4480 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4483 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4486 val = superclass.doMethod.call(this, attr, start, end);
4492 proto.setRuntimeAttribute = function(attr) {
4493 superclass.setRuntimeAttribute.call(this, attr);
4495 if (this.patterns.color.test(attr)) {
4496 var attributes = this.attributes;
4497 var start = this.parseColor(this.runtimeAttributes[attr].start);
4498 var end = this.parseColor(this.runtimeAttributes[attr].end);
4500 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4501 end = this.parseColor(attributes[attr].by);
4503 for (var i = 0, len = start.length; i < len; ++i) {
4504 end[i] = start[i] + end[i];
4508 this.runtimeAttributes[attr].start = start;
4509 this.runtimeAttributes[attr].end = end;
4515 * Portions of this file are based on pieces of Yahoo User Interface Library
4516 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4517 * YUI licensed under the BSD License:
4518 * http://developer.yahoo.net/yui/license.txt
4519 * <script type="text/javascript">
4525 easeNone: function (t, b, c, d) {
4526 return c * t / d + b;
4530 easeIn: function (t, b, c, d) {
4531 return c * (t /= d) * t + b;
4535 easeOut: function (t, b, c, d) {
4536 return -c * (t /= d) * (t - 2) + b;
4540 easeBoth: function (t, b, c, d) {
4541 if ((t /= d / 2) < 1) {
4542 return c / 2 * t * t + b;
4545 return -c / 2 * ((--t) * (t - 2) - 1) + b;
4549 easeInStrong: function (t, b, c, d) {
4550 return c * (t /= d) * t * t * t + b;
4554 easeOutStrong: function (t, b, c, d) {
4555 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4559 easeBothStrong: function (t, b, c, d) {
4560 if ((t /= d / 2) < 1) {
4561 return c / 2 * t * t * t * t + b;
4564 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4569 elasticIn: function (t, b, c, d, a, p) {
4573 if ((t /= d) == 1) {
4580 if (!a || a < Math.abs(c)) {
4585 var s = p / (2 * Math.PI) * Math.asin(c / a);
4588 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4592 elasticOut: function (t, b, c, d, a, p) {
4596 if ((t /= d) == 1) {
4603 if (!a || a < Math.abs(c)) {
4608 var s = p / (2 * Math.PI) * Math.asin(c / a);
4611 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4615 elasticBoth: function (t, b, c, d, a, p) {
4620 if ((t /= d / 2) == 2) {
4628 if (!a || a < Math.abs(c)) {
4633 var s = p / (2 * Math.PI) * Math.asin(c / a);
4637 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4638 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4640 return a * Math.pow(2, -10 * (t -= 1)) *
4641 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4646 backIn: function (t, b, c, d, s) {
4647 if (typeof s == 'undefined') {
4650 return c * (t /= d) * t * ((s + 1) * t - s) + b;
4654 backOut: function (t, b, c, d, s) {
4655 if (typeof s == 'undefined') {
4658 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4662 backBoth: function (t, b, c, d, s) {
4663 if (typeof s == 'undefined') {
4667 if ((t /= d / 2 ) < 1) {
4668 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4670 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4674 bounceIn: function (t, b, c, d) {
4675 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4679 bounceOut: function (t, b, c, d) {
4680 if ((t /= d) < (1 / 2.75)) {
4681 return c * (7.5625 * t * t) + b;
4682 } else if (t < (2 / 2.75)) {
4683 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4684 } else if (t < (2.5 / 2.75)) {
4685 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4687 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4691 bounceBoth: function (t, b, c, d) {
4693 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4695 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4698 * Portions of this file are based on pieces of Yahoo User Interface Library
4699 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4700 * YUI licensed under the BSD License:
4701 * http://developer.yahoo.net/yui/license.txt
4702 * <script type="text/javascript">
4706 Roo.lib.Motion = function(el, attributes, duration, method) {
4708 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4712 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4716 var superclass = Y.Motion.superclass;
4717 var proto = Y.Motion.prototype;
4719 proto.toString = function() {
4720 var el = this.getEl();
4721 var id = el.id || el.tagName;
4722 return ("Motion " + id);
4725 proto.patterns.points = /^points$/i;
4727 proto.setAttribute = function(attr, val, unit) {
4728 if (this.patterns.points.test(attr)) {
4729 unit = unit || 'px';
4730 superclass.setAttribute.call(this, 'left', val[0], unit);
4731 superclass.setAttribute.call(this, 'top', val[1], unit);
4733 superclass.setAttribute.call(this, attr, val, unit);
4737 proto.getAttribute = function(attr) {
4738 if (this.patterns.points.test(attr)) {
4740 superclass.getAttribute.call(this, 'left'),
4741 superclass.getAttribute.call(this, 'top')
4744 val = superclass.getAttribute.call(this, attr);
4750 proto.doMethod = function(attr, start, end) {
4753 if (this.patterns.points.test(attr)) {
4754 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4755 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4757 val = superclass.doMethod.call(this, attr, start, end);
4762 proto.setRuntimeAttribute = function(attr) {
4763 if (this.patterns.points.test(attr)) {
4764 var el = this.getEl();
4765 var attributes = this.attributes;
4767 var control = attributes['points']['control'] || [];
4771 if (control.length > 0 && !(control[0] instanceof Array)) {
4772 control = [control];
4775 for (i = 0,len = control.length; i < len; ++i) {
4776 tmp[i] = control[i];
4781 Roo.fly(el).position();
4783 if (isset(attributes['points']['from'])) {
4784 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4787 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4790 start = this.getAttribute('points');
4793 if (isset(attributes['points']['to'])) {
4794 end = translateValues.call(this, attributes['points']['to'], start);
4796 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4797 for (i = 0,len = control.length; i < len; ++i) {
4798 control[i] = translateValues.call(this, control[i], start);
4802 } else if (isset(attributes['points']['by'])) {
4803 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4805 for (i = 0,len = control.length; i < len; ++i) {
4806 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4810 this.runtimeAttributes[attr] = [start];
4812 if (control.length > 0) {
4813 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4816 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4819 superclass.setRuntimeAttribute.call(this, attr);
4823 var translateValues = function(val, start) {
4824 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4825 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4830 var isset = function(prop) {
4831 return (typeof prop !== 'undefined');
4835 * Portions of this file are based on pieces of Yahoo User Interface Library
4836 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4837 * YUI licensed under the BSD License:
4838 * http://developer.yahoo.net/yui/license.txt
4839 * <script type="text/javascript">
4843 Roo.lib.Scroll = function(el, attributes, duration, method) {
4845 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4849 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4853 var superclass = Y.Scroll.superclass;
4854 var proto = Y.Scroll.prototype;
4856 proto.toString = function() {
4857 var el = this.getEl();
4858 var id = el.id || el.tagName;
4859 return ("Scroll " + id);
4862 proto.doMethod = function(attr, start, end) {
4865 if (attr == 'scroll') {
4867 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4868 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4872 val = superclass.doMethod.call(this, attr, start, end);
4877 proto.getAttribute = function(attr) {
4879 var el = this.getEl();
4881 if (attr == 'scroll') {
4882 val = [ el.scrollLeft, el.scrollTop ];
4884 val = superclass.getAttribute.call(this, attr);
4890 proto.setAttribute = function(attr, val, unit) {
4891 var el = this.getEl();
4893 if (attr == 'scroll') {
4894 el.scrollLeft = val[0];
4895 el.scrollTop = val[1];
4897 superclass.setAttribute.call(this, attr, val, unit);
4903 * Ext JS Library 1.1.1
4904 * Copyright(c) 2006-2007, Ext JS, LLC.
4906 * Originally Released Under LGPL - original licence link has changed is not relivant.
4909 * <script type="text/javascript">
4913 // nasty IE9 hack - what a pile of crap that is..
4915 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4916 Range.prototype.createContextualFragment = function (html) {
4917 var doc = window.document;
4918 var container = doc.createElement("div");
4919 container.innerHTML = html;
4920 var frag = doc.createDocumentFragment(), n;
4921 while ((n = container.firstChild)) {
4922 frag.appendChild(n);
4929 * @class Roo.DomHelper
4930 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4931 * 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>.
4934 Roo.DomHelper = function(){
4935 var tempTableEl = null;
4936 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4937 var tableRe = /^table|tbody|tr|td$/i;
4939 // build as innerHTML where available
4941 var createHtml = function(o){
4942 if(typeof o == 'string'){
4951 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4952 if(attr == "style"){
4954 if(typeof s == "function"){
4957 if(typeof s == "string"){
4958 b += ' style="' + s + '"';
4959 }else if(typeof s == "object"){
4962 if(typeof s[key] != "function"){
4963 b += key + ":" + s[key] + ";";
4970 b += ' class="' + o["cls"] + '"';
4971 }else if(attr == "htmlFor"){
4972 b += ' for="' + o["htmlFor"] + '"';
4974 b += " " + attr + '="' + o[attr] + '"';
4978 if(emptyTags.test(o.tag)){
4982 var cn = o.children || o.cn;
4984 //http://bugs.kde.org/show_bug.cgi?id=71506
4985 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4986 for(var i = 0, len = cn.length; i < len; i++) {
4987 b += createHtml(cn[i], b);
4990 b += createHtml(cn, b);
4996 b += "</" + o.tag + ">";
5003 var createDom = function(o, parentNode){
5005 // defininition craeted..
5007 if (o.ns && o.ns != 'html') {
5009 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5010 xmlns[o.ns] = o.xmlns;
5013 if (typeof(xmlns[o.ns]) == 'undefined') {
5014 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5020 if (typeof(o) == 'string') {
5021 return parentNode.appendChild(document.createTextNode(o));
5023 o.tag = o.tag || div;
5024 if (o.ns && Roo.isIE) {
5026 o.tag = o.ns + ':' + o.tag;
5029 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
5030 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5033 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
5034 attr == "style" || typeof o[attr] == "function") { continue; }
5036 if(attr=="cls" && Roo.isIE){
5037 el.className = o["cls"];
5039 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5045 Roo.DomHelper.applyStyles(el, o.style);
5046 var cn = o.children || o.cn;
5048 //http://bugs.kde.org/show_bug.cgi?id=71506
5049 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5050 for(var i = 0, len = cn.length; i < len; i++) {
5051 createDom(cn[i], el);
5058 el.innerHTML = o.html;
5061 parentNode.appendChild(el);
5066 var ieTable = function(depth, s, h, e){
5067 tempTableEl.innerHTML = [s, h, e].join('');
5068 var i = -1, el = tempTableEl;
5069 while(++i < depth && el.firstChild){
5075 // kill repeat to save bytes
5079 tbe = '</tbody>'+te,
5085 * Nasty code for IE's broken table implementation
5087 var insertIntoTable = function(tag, where, el, html){
5089 tempTableEl = document.createElement('div');
5094 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5097 if(where == 'beforebegin'){
5101 before = el.nextSibling;
5104 node = ieTable(4, trs, html, tre);
5106 else if(tag == 'tr'){
5107 if(where == 'beforebegin'){
5110 node = ieTable(3, tbs, html, tbe);
5111 } else if(where == 'afterend'){
5112 before = el.nextSibling;
5114 node = ieTable(3, tbs, html, tbe);
5115 } else{ // INTO a TR
5116 if(where == 'afterbegin'){
5117 before = el.firstChild;
5119 node = ieTable(4, trs, html, tre);
5121 } else if(tag == 'tbody'){
5122 if(where == 'beforebegin'){
5125 node = ieTable(2, ts, html, te);
5126 } else if(where == 'afterend'){
5127 before = el.nextSibling;
5129 node = ieTable(2, ts, html, te);
5131 if(where == 'afterbegin'){
5132 before = el.firstChild;
5134 node = ieTable(3, tbs, html, tbe);
5137 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5140 if(where == 'afterbegin'){
5141 before = el.firstChild;
5143 node = ieTable(2, ts, html, te);
5145 el.insertBefore(node, before);
5150 /** True to force the use of DOM instead of html fragments @type Boolean */
5154 * Returns the markup for the passed Element(s) config
5155 * @param {Object} o The Dom object spec (and children)
5158 markup : function(o){
5159 return createHtml(o);
5163 * Applies a style specification to an element
5164 * @param {String/HTMLElement} el The element to apply styles to
5165 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5166 * a function which returns such a specification.
5168 applyStyles : function(el, styles){
5171 if(typeof styles == "string"){
5172 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5174 while ((matches = re.exec(styles)) != null){
5175 el.setStyle(matches[1], matches[2]);
5177 }else if (typeof styles == "object"){
5178 for (var style in styles){
5179 el.setStyle(style, styles[style]);
5181 }else if (typeof styles == "function"){
5182 Roo.DomHelper.applyStyles(el, styles.call());
5188 * Inserts an HTML fragment into the Dom
5189 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5190 * @param {HTMLElement} el The context element
5191 * @param {String} html The HTML fragmenet
5192 * @return {HTMLElement} The new node
5194 insertHtml : function(where, el, html){
5195 where = where.toLowerCase();
5196 if(el.insertAdjacentHTML){
5197 if(tableRe.test(el.tagName)){
5199 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5205 el.insertAdjacentHTML('BeforeBegin', html);
5206 return el.previousSibling;
5208 el.insertAdjacentHTML('AfterBegin', html);
5209 return el.firstChild;
5211 el.insertAdjacentHTML('BeforeEnd', html);
5212 return el.lastChild;
5214 el.insertAdjacentHTML('AfterEnd', html);
5215 return el.nextSibling;
5217 throw 'Illegal insertion point -> "' + where + '"';
5219 var range = el.ownerDocument.createRange();
5223 range.setStartBefore(el);
5224 frag = range.createContextualFragment(html);
5225 el.parentNode.insertBefore(frag, el);
5226 return el.previousSibling;
5229 range.setStartBefore(el.firstChild);
5230 frag = range.createContextualFragment(html);
5231 el.insertBefore(frag, el.firstChild);
5232 return el.firstChild;
5234 el.innerHTML = html;
5235 return el.firstChild;
5239 range.setStartAfter(el.lastChild);
5240 frag = range.createContextualFragment(html);
5241 el.appendChild(frag);
5242 return el.lastChild;
5244 el.innerHTML = html;
5245 return el.lastChild;
5248 range.setStartAfter(el);
5249 frag = range.createContextualFragment(html);
5250 el.parentNode.insertBefore(frag, el.nextSibling);
5251 return el.nextSibling;
5253 throw 'Illegal insertion point -> "' + where + '"';
5257 * Creates new Dom element(s) and inserts them before el
5258 * @param {String/HTMLElement/Element} el The context element
5259 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5260 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5261 * @return {HTMLElement/Roo.Element} The new node
5263 insertBefore : function(el, o, returnElement){
5264 return this.doInsert(el, o, returnElement, "beforeBegin");
5268 * Creates new Dom element(s) and inserts them after el
5269 * @param {String/HTMLElement/Element} el The context element
5270 * @param {Object} o The Dom object spec (and children)
5271 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5272 * @return {HTMLElement/Roo.Element} The new node
5274 insertAfter : function(el, o, returnElement){
5275 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5279 * Creates new Dom element(s) and inserts them as the first child of el
5280 * @param {String/HTMLElement/Element} el The context element
5281 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5282 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5283 * @return {HTMLElement/Roo.Element} The new node
5285 insertFirst : function(el, o, returnElement){
5286 return this.doInsert(el, o, returnElement, "afterBegin");
5290 doInsert : function(el, o, returnElement, pos, sibling){
5291 el = Roo.getDom(el);
5293 if(this.useDom || o.ns){
5294 newNode = createDom(o, null);
5295 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5297 var html = createHtml(o);
5298 newNode = this.insertHtml(pos, el, html);
5300 return returnElement ? Roo.get(newNode, true) : newNode;
5304 * Creates new Dom element(s) and appends them to el
5305 * @param {String/HTMLElement/Element} el The context element
5306 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5307 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5308 * @return {HTMLElement/Roo.Element} The new node
5310 append : function(el, o, returnElement){
5311 el = Roo.getDom(el);
5313 if(this.useDom || o.ns){
5314 newNode = createDom(o, null);
5315 el.appendChild(newNode);
5317 var html = createHtml(o);
5318 newNode = this.insertHtml("beforeEnd", el, html);
5320 return returnElement ? Roo.get(newNode, true) : newNode;
5324 * Creates new Dom element(s) and overwrites the contents of el with them
5325 * @param {String/HTMLElement/Element} el The context element
5326 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5327 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5328 * @return {HTMLElement/Roo.Element} The new node
5330 overwrite : function(el, o, returnElement){
5331 el = Roo.getDom(el);
5334 while (el.childNodes.length) {
5335 el.removeChild(el.firstChild);
5339 el.innerHTML = createHtml(o);
5342 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5346 * Creates a new Roo.DomHelper.Template from the Dom object spec
5347 * @param {Object} o The Dom object spec (and children)
5348 * @return {Roo.DomHelper.Template} The new template
5350 createTemplate : function(o){
5351 var html = createHtml(o);
5352 return new Roo.Template(html);
5358 * Ext JS Library 1.1.1
5359 * Copyright(c) 2006-2007, Ext JS, LLC.
5361 * Originally Released Under LGPL - original licence link has changed is not relivant.
5364 * <script type="text/javascript">
5368 * @class Roo.Template
5369 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5370 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5373 var t = new Roo.Template({
5374 html : '<div name="{id}">' +
5375 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
5377 myformat: function (value, allValues) {
5378 return 'XX' + value;
5381 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5383 * For more information see this blog post with examples:
5384 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5385 - Create Elements using DOM, HTML fragments and Templates</a>.
5387 * @param {Object} cfg - Configuration object.
5389 Roo.Template = function(cfg){
5391 if(cfg instanceof Array){
5393 }else if(arguments.length > 1){
5394 cfg = Array.prototype.join.call(arguments, "");
5398 if (typeof(cfg) == 'object') {
5409 Roo.Template.prototype = {
5412 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5418 * @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..
5419 * it should be fixed so that template is observable...
5423 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5431 * Returns an HTML fragment of this template with the specified values applied.
5432 * @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'})
5433 * @return {String} The HTML fragment
5438 applyTemplate : function(values){
5439 //Roo.log(["applyTemplate", values]);
5443 return this.compiled(values);
5445 var useF = this.disableFormats !== true;
5446 var fm = Roo.util.Format, tpl = this;
5447 var fn = function(m, name, format, args){
5449 if(format.substr(0, 5) == "this."){
5450 return tpl.call(format.substr(5), values[name], values);
5453 // quoted values are required for strings in compiled templates,
5454 // but for non compiled we need to strip them
5455 // quoted reversed for jsmin
5456 var re = /^\s*['"](.*)["']\s*$/;
5457 args = args.split(',');
5458 for(var i = 0, len = args.length; i < len; i++){
5459 args[i] = args[i].replace(re, "$1");
5461 args = [values[name]].concat(args);
5463 args = [values[name]];
5465 return fm[format].apply(fm, args);
5468 return values[name] !== undefined ? values[name] : "";
5471 return this.html.replace(this.re, fn);
5489 this.loading = true;
5490 this.compiled = false;
5492 var cx = new Roo.data.Connection();
5496 success : function (response) {
5500 _t.set(response.responseText,true);
5506 failure : function(response) {
5507 Roo.log("Template failed to load from " + _t.url);
5514 * Sets the HTML used as the template and optionally compiles it.
5515 * @param {String} html
5516 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5517 * @return {Roo.Template} this
5519 set : function(html, compile){
5521 this.compiled = false;
5529 * True to disable format functions (defaults to false)
5532 disableFormats : false,
5535 * The regular expression used to match template variables
5539 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5542 * Compiles the template into an internal function, eliminating the RegEx overhead.
5543 * @return {Roo.Template} this
5545 compile : function(){
5546 var fm = Roo.util.Format;
5547 var useF = this.disableFormats !== true;
5548 var sep = Roo.isGecko ? "+" : ",";
5549 var fn = function(m, name, format, args){
5551 args = args ? ',' + args : "";
5552 if(format.substr(0, 5) != "this."){
5553 format = "fm." + format + '(';
5555 format = 'this.call("'+ format.substr(5) + '", ';
5559 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5561 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5564 // branched to use + in gecko and [].join() in others
5566 body = "this.compiled = function(values){ return '" +
5567 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5570 body = ["this.compiled = function(values){ return ['"];
5571 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5572 body.push("'].join('');};");
5573 body = body.join('');
5583 // private function used to call members
5584 call : function(fnName, value, allValues){
5585 return this[fnName](value, allValues);
5589 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5590 * @param {String/HTMLElement/Roo.Element} el The context element
5591 * @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'})
5592 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5593 * @return {HTMLElement/Roo.Element} The new node or Element
5595 insertFirst: function(el, values, returnElement){
5596 return this.doInsert('afterBegin', el, values, returnElement);
5600 * Applies the supplied values to the template and inserts the new node(s) before el.
5601 * @param {String/HTMLElement/Roo.Element} el The context element
5602 * @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'})
5603 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5604 * @return {HTMLElement/Roo.Element} The new node or Element
5606 insertBefore: function(el, values, returnElement){
5607 return this.doInsert('beforeBegin', el, values, returnElement);
5611 * Applies the supplied values to the template and inserts the new node(s) after el.
5612 * @param {String/HTMLElement/Roo.Element} el The context element
5613 * @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'})
5614 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5615 * @return {HTMLElement/Roo.Element} The new node or Element
5617 insertAfter : function(el, values, returnElement){
5618 return this.doInsert('afterEnd', el, values, returnElement);
5622 * Applies the supplied values to the template and appends the new node(s) to el.
5623 * @param {String/HTMLElement/Roo.Element} el The context element
5624 * @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'})
5625 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5626 * @return {HTMLElement/Roo.Element} The new node or Element
5628 append : function(el, values, returnElement){
5629 return this.doInsert('beforeEnd', el, values, returnElement);
5632 doInsert : function(where, el, values, returnEl){
5633 el = Roo.getDom(el);
5634 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
5635 return returnEl ? Roo.get(newNode, true) : newNode;
5639 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
5640 * @param {String/HTMLElement/Roo.Element} el The context element
5641 * @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'})
5642 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5643 * @return {HTMLElement/Roo.Element} The new node or Element
5645 overwrite : function(el, values, returnElement){
5646 el = Roo.getDom(el);
5647 el.innerHTML = this.applyTemplate(values);
5648 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5652 * Alias for {@link #applyTemplate}
5655 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
5658 Roo.DomHelper.Template = Roo.Template;
5661 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
5662 * @param {String/HTMLElement} el A DOM element or its id
5663 * @returns {Roo.Template} The created template
5666 Roo.Template.from = function(el){
5667 el = Roo.getDom(el);
5668 return new Roo.Template(el.value || el.innerHTML);
5671 * Ext JS Library 1.1.1
5672 * Copyright(c) 2006-2007, Ext JS, LLC.
5674 * Originally Released Under LGPL - original licence link has changed is not relivant.
5677 * <script type="text/javascript">
5682 * This is code is also distributed under MIT license for use
5683 * with jQuery and prototype JavaScript libraries.
5686 * @class Roo.DomQuery
5687 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).
5689 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>
5692 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.
5694 <h4>Element Selectors:</h4>
5696 <li> <b>*</b> any element</li>
5697 <li> <b>E</b> an element with the tag E</li>
5698 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
5699 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
5700 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
5701 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
5703 <h4>Attribute Selectors:</h4>
5704 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5706 <li> <b>E[foo]</b> has an attribute "foo"</li>
5707 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5708 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5709 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5710 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5711 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5712 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5714 <h4>Pseudo Classes:</h4>
5716 <li> <b>E:first-child</b> E is the first child of its parent</li>
5717 <li> <b>E:last-child</b> E is the last child of its parent</li>
5718 <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>
5719 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5720 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5721 <li> <b>E:only-child</b> E is the only child of its parent</li>
5722 <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>
5723 <li> <b>E:first</b> the first E in the resultset</li>
5724 <li> <b>E:last</b> the last E in the resultset</li>
5725 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5726 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5727 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5728 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5729 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5730 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5731 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5732 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5733 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5735 <h4>CSS Value Selectors:</h4>
5737 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5738 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5739 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5740 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5741 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5742 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5746 Roo.DomQuery = function(){
5747 var cache = {}, simpleCache = {}, valueCache = {};
5748 var nonSpace = /\S/;
5749 var trimRe = /^\s+|\s+$/g;
5750 var tplRe = /\{(\d+)\}/g;
5751 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5752 var tagTokenRe = /^(#)?([\w-\*]+)/;
5753 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5755 function child(p, index){
5757 var n = p.firstChild;
5759 if(n.nodeType == 1){
5770 while((n = n.nextSibling) && n.nodeType != 1);
5775 while((n = n.previousSibling) && n.nodeType != 1);
5779 function children(d){
5780 var n = d.firstChild, ni = -1;
5782 var nx = n.nextSibling;
5783 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5793 function byClassName(c, a, v){
5797 var r = [], ri = -1, cn;
5798 for(var i = 0, ci; ci = c[i]; i++){
5802 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5803 +' ').indexOf(v) != -1){
5810 function attrValue(n, attr){
5811 if(!n.tagName && typeof n.length != "undefined"){
5820 if(attr == "class" || attr == "className"){
5821 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5823 return n.getAttribute(attr) || n[attr];
5827 function getNodes(ns, mode, tagName){
5828 var result = [], ri = -1, cs;
5832 tagName = tagName || "*";
5833 if(typeof ns.getElementsByTagName != "undefined"){
5837 for(var i = 0, ni; ni = ns[i]; i++){
5838 cs = ni.getElementsByTagName(tagName);
5839 for(var j = 0, ci; ci = cs[j]; j++){
5843 }else if(mode == "/" || mode == ">"){
5844 var utag = tagName.toUpperCase();
5845 for(var i = 0, ni, cn; ni = ns[i]; i++){
5846 cn = ni.children || ni.childNodes;
5847 for(var j = 0, cj; cj = cn[j]; j++){
5848 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5853 }else if(mode == "+"){
5854 var utag = tagName.toUpperCase();
5855 for(var i = 0, n; n = ns[i]; i++){
5856 while((n = n.nextSibling) && n.nodeType != 1);
5857 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5861 }else if(mode == "~"){
5862 for(var i = 0, n; n = ns[i]; i++){
5863 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5872 function concat(a, b){
5876 for(var i = 0, l = b.length; i < l; i++){
5882 function byTag(cs, tagName){
5883 if(cs.tagName || cs == document){
5889 var r = [], ri = -1;
5890 tagName = tagName.toLowerCase();
5891 for(var i = 0, ci; ci = cs[i]; i++){
5892 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5899 function byId(cs, attr, id){
5900 if(cs.tagName || cs == document){
5906 var r = [], ri = -1;
5907 for(var i = 0,ci; ci = cs[i]; i++){
5908 if(ci && ci.id == id){
5916 function byAttribute(cs, attr, value, op, custom){
5917 var r = [], ri = -1, st = custom=="{";
5918 var f = Roo.DomQuery.operators[op];
5919 for(var i = 0, ci; ci = cs[i]; i++){
5922 a = Roo.DomQuery.getStyle(ci, attr);
5924 else if(attr == "class" || attr == "className"){
5925 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
5926 }else if(attr == "for"){
5928 }else if(attr == "href"){
5929 a = ci.getAttribute("href", 2);
5931 a = ci.getAttribute(attr);
5933 if((f && f(a, value)) || (!f && a)){
5940 function byPseudo(cs, name, value){
5941 return Roo.DomQuery.pseudos[name](cs, value);
5944 // This is for IE MSXML which does not support expandos.
5945 // IE runs the same speed using setAttribute, however FF slows way down
5946 // and Safari completely fails so they need to continue to use expandos.
5947 var isIE = window.ActiveXObject ? true : false;
5949 // this eval is stop the compressor from
5950 // renaming the variable to something shorter
5952 /** eval:var:batch */
5957 function nodupIEXml(cs){
5959 cs[0].setAttribute("_nodup", d);
5961 for(var i = 1, len = cs.length; i < len; i++){
5963 if(!c.getAttribute("_nodup") != d){
5964 c.setAttribute("_nodup", d);
5968 for(var i = 0, len = cs.length; i < len; i++){
5969 cs[i].removeAttribute("_nodup");
5978 var len = cs.length, c, i, r = cs, cj, ri = -1;
5979 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5982 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5983 return nodupIEXml(cs);
5987 for(i = 1; c = cs[i]; i++){
5992 for(var j = 0; j < i; j++){
5995 for(j = i+1; cj = cs[j]; j++){
6007 function quickDiffIEXml(c1, c2){
6009 for(var i = 0, len = c1.length; i < len; i++){
6010 c1[i].setAttribute("_qdiff", d);
6013 for(var i = 0, len = c2.length; i < len; i++){
6014 if(c2[i].getAttribute("_qdiff") != d){
6015 r[r.length] = c2[i];
6018 for(var i = 0, len = c1.length; i < len; i++){
6019 c1[i].removeAttribute("_qdiff");
6024 function quickDiff(c1, c2){
6025 var len1 = c1.length;
6029 if(isIE && c1[0].selectSingleNode){
6030 return quickDiffIEXml(c1, c2);
6033 for(var i = 0; i < len1; i++){
6037 for(var i = 0, len = c2.length; i < len; i++){
6038 if(c2[i]._qdiff != d){
6039 r[r.length] = c2[i];
6045 function quickId(ns, mode, root, id){
6047 var d = root.ownerDocument || root;
6048 return d.getElementById(id);
6050 ns = getNodes(ns, mode, "*");
6051 return byId(ns, null, id);
6055 getStyle : function(el, name){
6056 return Roo.fly(el).getStyle(name);
6059 * Compiles a selector/xpath query into a reusable function. The returned function
6060 * takes one parameter "root" (optional), which is the context node from where the query should start.
6061 * @param {String} selector The selector/xpath query
6062 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6063 * @return {Function}
6065 compile : function(path, type){
6066 type = type || "select";
6068 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6069 var q = path, mode, lq;
6070 var tk = Roo.DomQuery.matchers;
6071 var tklen = tk.length;
6074 // accept leading mode switch
6075 var lmode = q.match(modeRe);
6076 if(lmode && lmode[1]){
6077 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6078 q = q.replace(lmode[1], "");
6080 // strip leading slashes
6081 while(path.substr(0, 1)=="/"){
6082 path = path.substr(1);
6085 while(q && lq != q){
6087 var tm = q.match(tagTokenRe);
6088 if(type == "select"){
6091 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6093 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6095 q = q.replace(tm[0], "");
6096 }else if(q.substr(0, 1) != '@'){
6097 fn[fn.length] = 'n = getNodes(n, mode, "*");';
6102 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6104 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6106 q = q.replace(tm[0], "");
6109 while(!(mm = q.match(modeRe))){
6110 var matched = false;
6111 for(var j = 0; j < tklen; j++){
6113 var m = q.match(t.re);
6115 fn[fn.length] = t.select.replace(tplRe, function(x, i){
6118 q = q.replace(m[0], "");
6123 // prevent infinite loop on bad selector
6125 throw 'Error parsing selector, parsing failed at "' + q + '"';
6129 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6130 q = q.replace(mm[1], "");
6133 fn[fn.length] = "return nodup(n);\n}";
6136 * list of variables that need from compression as they are used by eval.
6146 * eval:var:byClassName
6148 * eval:var:byAttribute
6149 * eval:var:attrValue
6157 * Selects a group of elements.
6158 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6159 * @param {Node} root (optional) The start of the query (defaults to document).
6162 select : function(path, root, type){
6163 if(!root || root == document){
6166 if(typeof root == "string"){
6167 root = document.getElementById(root);
6169 var paths = path.split(",");
6171 for(var i = 0, len = paths.length; i < len; i++){
6172 var p = paths[i].replace(trimRe, "");
6174 cache[p] = Roo.DomQuery.compile(p);
6176 throw p + " is not a valid selector";
6179 var result = cache[p](root);
6180 if(result && result != document){
6181 results = results.concat(result);
6184 if(paths.length > 1){
6185 return nodup(results);
6191 * Selects a single element.
6192 * @param {String} selector The selector/xpath query
6193 * @param {Node} root (optional) The start of the query (defaults to document).
6196 selectNode : function(path, root){
6197 return Roo.DomQuery.select(path, root)[0];
6201 * Selects the value of a node, optionally replacing null with the defaultValue.
6202 * @param {String} selector The selector/xpath query
6203 * @param {Node} root (optional) The start of the query (defaults to document).
6204 * @param {String} defaultValue
6206 selectValue : function(path, root, defaultValue){
6207 path = path.replace(trimRe, "");
6208 if(!valueCache[path]){
6209 valueCache[path] = Roo.DomQuery.compile(path, "select");
6211 var n = valueCache[path](root);
6212 n = n[0] ? n[0] : n;
6213 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6214 return ((v === null||v === undefined||v==='') ? defaultValue : v);
6218 * Selects the value of a node, parsing integers and floats.
6219 * @param {String} selector The selector/xpath query
6220 * @param {Node} root (optional) The start of the query (defaults to document).
6221 * @param {Number} defaultValue
6224 selectNumber : function(path, root, defaultValue){
6225 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6226 return parseFloat(v);
6230 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6231 * @param {String/HTMLElement/Array} el An element id, element or array of elements
6232 * @param {String} selector The simple selector to test
6235 is : function(el, ss){
6236 if(typeof el == "string"){
6237 el = document.getElementById(el);
6239 var isArray = (el instanceof Array);
6240 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6241 return isArray ? (result.length == el.length) : (result.length > 0);
6245 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6246 * @param {Array} el An array of elements to filter
6247 * @param {String} selector The simple selector to test
6248 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6249 * the selector instead of the ones that match
6252 filter : function(els, ss, nonMatches){
6253 ss = ss.replace(trimRe, "");
6254 if(!simpleCache[ss]){
6255 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6257 var result = simpleCache[ss](els);
6258 return nonMatches ? quickDiff(result, els) : result;
6262 * Collection of matching regular expressions and code snippets.
6266 select: 'n = byClassName(n, null, " {1} ");'
6268 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6269 select: 'n = byPseudo(n, "{1}", "{2}");'
6271 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6272 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6275 select: 'n = byId(n, null, "{1}");'
6278 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6283 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6284 * 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, > <.
6287 "=" : function(a, v){
6290 "!=" : function(a, v){
6293 "^=" : function(a, v){
6294 return a && a.substr(0, v.length) == v;
6296 "$=" : function(a, v){
6297 return a && a.substr(a.length-v.length) == v;
6299 "*=" : function(a, v){
6300 return a && a.indexOf(v) !== -1;
6302 "%=" : function(a, v){
6303 return (a % v) == 0;
6305 "|=" : function(a, v){
6306 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6308 "~=" : function(a, v){
6309 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6314 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6315 * and the argument (if any) supplied in the selector.
6318 "first-child" : function(c){
6319 var r = [], ri = -1, n;
6320 for(var i = 0, ci; ci = n = c[i]; i++){
6321 while((n = n.previousSibling) && n.nodeType != 1);
6329 "last-child" : function(c){
6330 var r = [], ri = -1, n;
6331 for(var i = 0, ci; ci = n = c[i]; i++){
6332 while((n = n.nextSibling) && n.nodeType != 1);
6340 "nth-child" : function(c, a) {
6341 var r = [], ri = -1;
6342 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6343 var f = (m[1] || 1) - 0, l = m[2] - 0;
6344 for(var i = 0, n; n = c[i]; i++){
6345 var pn = n.parentNode;
6346 if (batch != pn._batch) {
6348 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6349 if(cn.nodeType == 1){
6356 if (l == 0 || n.nodeIndex == l){
6359 } else if ((n.nodeIndex + l) % f == 0){
6367 "only-child" : function(c){
6368 var r = [], ri = -1;;
6369 for(var i = 0, ci; ci = c[i]; i++){
6370 if(!prev(ci) && !next(ci)){
6377 "empty" : function(c){
6378 var r = [], ri = -1;
6379 for(var i = 0, ci; ci = c[i]; i++){
6380 var cns = ci.childNodes, j = 0, cn, empty = true;
6383 if(cn.nodeType == 1 || cn.nodeType == 3){
6395 "contains" : function(c, v){
6396 var r = [], ri = -1;
6397 for(var i = 0, ci; ci = c[i]; i++){
6398 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6405 "nodeValue" : function(c, v){
6406 var r = [], ri = -1;
6407 for(var i = 0, ci; ci = c[i]; i++){
6408 if(ci.firstChild && ci.firstChild.nodeValue == v){
6415 "checked" : function(c){
6416 var r = [], ri = -1;
6417 for(var i = 0, ci; ci = c[i]; i++){
6418 if(ci.checked == true){
6425 "not" : function(c, ss){
6426 return Roo.DomQuery.filter(c, ss, true);
6429 "odd" : function(c){
6430 return this["nth-child"](c, "odd");
6433 "even" : function(c){
6434 return this["nth-child"](c, "even");
6437 "nth" : function(c, a){
6438 return c[a-1] || [];
6441 "first" : function(c){
6445 "last" : function(c){
6446 return c[c.length-1] || [];
6449 "has" : function(c, ss){
6450 var s = Roo.DomQuery.select;
6451 var r = [], ri = -1;
6452 for(var i = 0, ci; ci = c[i]; i++){
6453 if(s(ss, ci).length > 0){
6460 "next" : function(c, ss){
6461 var is = Roo.DomQuery.is;
6462 var r = [], ri = -1;
6463 for(var i = 0, ci; ci = c[i]; i++){
6472 "prev" : function(c, ss){
6473 var is = Roo.DomQuery.is;
6474 var r = [], ri = -1;
6475 for(var i = 0, ci; ci = c[i]; i++){
6488 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6489 * @param {String} path The selector/xpath query
6490 * @param {Node} root (optional) The start of the query (defaults to document).
6495 Roo.query = Roo.DomQuery.select;
6498 * Ext JS Library 1.1.1
6499 * Copyright(c) 2006-2007, Ext JS, LLC.
6501 * Originally Released Under LGPL - original licence link has changed is not relivant.
6504 * <script type="text/javascript">
6508 * @class Roo.util.Observable
6509 * Base class that provides a common interface for publishing events. Subclasses are expected to
6510 * to have a property "events" with all the events defined.<br>
6513 Employee = function(name){
6520 Roo.extend(Employee, Roo.util.Observable);
6522 * @param {Object} config properties to use (incuding events / listeners)
6525 Roo.util.Observable = function(cfg){
6528 this.addEvents(cfg.events || {});
6530 delete cfg.events; // make sure
6533 Roo.apply(this, cfg);
6536 this.on(this.listeners);
6537 delete this.listeners;
6540 Roo.util.Observable.prototype = {
6542 * @cfg {Object} listeners list of events and functions to call for this object,
6546 'click' : function(e) {
6556 * Fires the specified event with the passed parameters (minus the event name).
6557 * @param {String} eventName
6558 * @param {Object...} args Variable number of parameters are passed to handlers
6559 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6561 fireEvent : function(){
6562 var ce = this.events[arguments[0].toLowerCase()];
6563 if(typeof ce == "object"){
6564 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6571 filterOptRe : /^(?:scope|delay|buffer|single)$/,
6574 * Appends an event handler to this component
6575 * @param {String} eventName The type of event to listen for
6576 * @param {Function} handler The method the event invokes
6577 * @param {Object} scope (optional) The scope in which to execute the handler
6578 * function. The handler function's "this" context.
6579 * @param {Object} options (optional) An object containing handler configuration
6580 * properties. This may contain any of the following properties:<ul>
6581 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6582 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6583 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6584 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6585 * by the specified number of milliseconds. If the event fires again within that time, the original
6586 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6589 * <b>Combining Options</b><br>
6590 * Using the options argument, it is possible to combine different types of listeners:<br>
6592 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6594 el.on('click', this.onClick, this, {
6601 * <b>Attaching multiple handlers in 1 call</b><br>
6602 * The method also allows for a single argument to be passed which is a config object containing properties
6603 * which specify multiple handlers.
6612 fn: this.onMouseOver,
6616 fn: this.onMouseOut,
6622 * Or a shorthand syntax which passes the same scope object to all handlers:
6625 'click': this.onClick,
6626 'mouseover': this.onMouseOver,
6627 'mouseout': this.onMouseOut,
6632 addListener : function(eventName, fn, scope, o){
6633 if(typeof eventName == "object"){
6636 if(this.filterOptRe.test(e)){
6639 if(typeof o[e] == "function"){
6641 this.addListener(e, o[e], o.scope, o);
6643 // individual options
6644 this.addListener(e, o[e].fn, o[e].scope, o[e]);
6649 o = (!o || typeof o == "boolean") ? {} : o;
6650 eventName = eventName.toLowerCase();
6651 var ce = this.events[eventName] || true;
6652 if(typeof ce == "boolean"){
6653 ce = new Roo.util.Event(this, eventName);
6654 this.events[eventName] = ce;
6656 ce.addListener(fn, scope, o);
6660 * Removes a listener
6661 * @param {String} eventName The type of event to listen for
6662 * @param {Function} handler The handler to remove
6663 * @param {Object} scope (optional) The scope (this object) for the handler
6665 removeListener : function(eventName, fn, scope){
6666 var ce = this.events[eventName.toLowerCase()];
6667 if(typeof ce == "object"){
6668 ce.removeListener(fn, scope);
6673 * Removes all listeners for this object
6675 purgeListeners : function(){
6676 for(var evt in this.events){
6677 if(typeof this.events[evt] == "object"){
6678 this.events[evt].clearListeners();
6683 relayEvents : function(o, events){
6684 var createHandler = function(ename){
6687 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
6690 for(var i = 0, len = events.length; i < len; i++){
6691 var ename = events[i];
6692 if(!this.events[ename]){
6693 this.events[ename] = true;
6695 o.on(ename, createHandler(ename), this);
6700 * Used to define events on this Observable
6701 * @param {Object} object The object with the events defined
6703 addEvents : function(o){
6707 Roo.applyIf(this.events, o);
6711 * Checks to see if this object has any listeners for a specified event
6712 * @param {String} eventName The name of the event to check for
6713 * @return {Boolean} True if the event is being listened for, else false
6715 hasListener : function(eventName){
6716 var e = this.events[eventName];
6717 return typeof e == "object" && e.listeners.length > 0;
6721 * Appends an event handler to this element (shorthand for addListener)
6722 * @param {String} eventName The type of event to listen for
6723 * @param {Function} handler The method the event invokes
6724 * @param {Object} scope (optional) The scope in which to execute the handler
6725 * function. The handler function's "this" context.
6726 * @param {Object} options (optional)
6729 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6731 * Removes a listener (shorthand for removeListener)
6732 * @param {String} eventName The type of event to listen for
6733 * @param {Function} handler The handler to remove
6734 * @param {Object} scope (optional) The scope (this object) for the handler
6737 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6740 * Starts capture on the specified Observable. All events will be passed
6741 * to the supplied function with the event name + standard signature of the event
6742 * <b>before</b> the event is fired. If the supplied function returns false,
6743 * the event will not fire.
6744 * @param {Observable} o The Observable to capture
6745 * @param {Function} fn The function to call
6746 * @param {Object} scope (optional) The scope (this object) for the fn
6749 Roo.util.Observable.capture = function(o, fn, scope){
6750 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6754 * Removes <b>all</b> added captures from the Observable.
6755 * @param {Observable} o The Observable to release
6758 Roo.util.Observable.releaseCapture = function(o){
6759 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6764 var createBuffered = function(h, o, scope){
6765 var task = new Roo.util.DelayedTask();
6767 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6771 var createSingle = function(h, e, fn, scope){
6773 e.removeListener(fn, scope);
6774 return h.apply(scope, arguments);
6778 var createDelayed = function(h, o, scope){
6780 var args = Array.prototype.slice.call(arguments, 0);
6781 setTimeout(function(){
6782 h.apply(scope, args);
6787 Roo.util.Event = function(obj, name){
6790 this.listeners = [];
6793 Roo.util.Event.prototype = {
6794 addListener : function(fn, scope, options){
6795 var o = options || {};
6796 scope = scope || this.obj;
6797 if(!this.isListening(fn, scope)){
6798 var l = {fn: fn, scope: scope, options: o};
6801 h = createDelayed(h, o, scope);
6804 h = createSingle(h, this, fn, scope);
6807 h = createBuffered(h, o, scope);
6810 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6811 this.listeners.push(l);
6813 this.listeners = this.listeners.slice(0);
6814 this.listeners.push(l);
6819 findListener : function(fn, scope){
6820 scope = scope || this.obj;
6821 var ls = this.listeners;
6822 for(var i = 0, len = ls.length; i < len; i++){
6824 if(l.fn == fn && l.scope == scope){
6831 isListening : function(fn, scope){
6832 return this.findListener(fn, scope) != -1;
6835 removeListener : function(fn, scope){
6837 if((index = this.findListener(fn, scope)) != -1){
6839 this.listeners.splice(index, 1);
6841 this.listeners = this.listeners.slice(0);
6842 this.listeners.splice(index, 1);
6849 clearListeners : function(){
6850 this.listeners = [];
6854 var ls = this.listeners, scope, len = ls.length;
6857 var args = Array.prototype.slice.call(arguments, 0);
6858 for(var i = 0; i < len; i++){
6860 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6861 this.firing = false;
6865 this.firing = false;
6872 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6879 * @class Roo.Document
6880 * @extends Roo.util.Observable
6881 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6883 * @param {Object} config the methods and properties of the 'base' class for the application.
6885 * Generic Page handler - implement this to start your app..
6888 * MyProject = new Roo.Document({
6890 'load' : true // your events..
6893 'ready' : function() {
6894 // fired on Roo.onReady()
6899 Roo.Document = function(cfg) {
6904 Roo.util.Observable.call(this,cfg);
6908 Roo.onReady(function() {
6909 _this.fireEvent('ready');
6915 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6917 * Ext JS Library 1.1.1
6918 * Copyright(c) 2006-2007, Ext JS, LLC.
6920 * Originally Released Under LGPL - original licence link has changed is not relivant.
6923 * <script type="text/javascript">
6927 * @class Roo.EventManager
6928 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6929 * several useful events directly.
6930 * See {@link Roo.EventObject} for more details on normalized event objects.
6933 Roo.EventManager = function(){
6934 var docReadyEvent, docReadyProcId, docReadyState = false;
6935 var resizeEvent, resizeTask, textEvent, textSize;
6936 var E = Roo.lib.Event;
6937 var D = Roo.lib.Dom;
6942 var fireDocReady = function(){
6944 docReadyState = true;
6947 clearInterval(docReadyProcId);
6949 if(Roo.isGecko || Roo.isOpera) {
6950 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6953 var defer = document.getElementById("ie-deferred-loader");
6955 defer.onreadystatechange = null;
6956 defer.parentNode.removeChild(defer);
6960 docReadyEvent.fire();
6961 docReadyEvent.clearListeners();
6966 var initDocReady = function(){
6967 docReadyEvent = new Roo.util.Event();
6968 if(Roo.isGecko || Roo.isOpera) {
6969 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6971 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6972 var defer = document.getElementById("ie-deferred-loader");
6973 defer.onreadystatechange = function(){
6974 if(this.readyState == "complete"){
6978 }else if(Roo.isSafari){
6979 docReadyProcId = setInterval(function(){
6980 var rs = document.readyState;
6981 if(rs == "complete") {
6986 // no matter what, make sure it fires on load
6987 E.on(window, "load", fireDocReady);
6990 var createBuffered = function(h, o){
6991 var task = new Roo.util.DelayedTask(h);
6993 // create new event object impl so new events don't wipe out properties
6994 e = new Roo.EventObjectImpl(e);
6995 task.delay(o.buffer, h, null, [e]);
6999 var createSingle = function(h, el, ename, fn){
7001 Roo.EventManager.removeListener(el, ename, fn);
7006 var createDelayed = function(h, o){
7008 // create new event object impl so new events don't wipe out properties
7009 e = new Roo.EventObjectImpl(e);
7010 setTimeout(function(){
7015 var transitionEndVal = false;
7017 var transitionEnd = function()
7019 if (transitionEndVal) {
7020 return transitionEndVal;
7022 var el = document.createElement('div');
7024 var transEndEventNames = {
7025 WebkitTransition : 'webkitTransitionEnd',
7026 MozTransition : 'transitionend',
7027 OTransition : 'oTransitionEnd otransitionend',
7028 transition : 'transitionend'
7031 for (var name in transEndEventNames) {
7032 if (el.style[name] !== undefined) {
7033 transitionEndVal = transEndEventNames[name];
7034 return transitionEndVal ;
7041 var listen = function(element, ename, opt, fn, scope)
7043 var o = (!opt || typeof opt == "boolean") ? {} : opt;
7044 fn = fn || o.fn; scope = scope || o.scope;
7045 var el = Roo.getDom(element);
7049 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7052 if (ename == 'transitionend') {
7053 ename = transitionEnd();
7055 var h = function(e){
7056 e = Roo.EventObject.setEvent(e);
7059 t = e.getTarget(o.delegate, el);
7066 if(o.stopEvent === true){
7069 if(o.preventDefault === true){
7072 if(o.stopPropagation === true){
7073 e.stopPropagation();
7076 if(o.normalized === false){
7080 fn.call(scope || el, e, t, o);
7083 h = createDelayed(h, o);
7086 h = createSingle(h, el, ename, fn);
7089 h = createBuffered(h, o);
7092 fn._handlers = fn._handlers || [];
7095 fn._handlers.push([Roo.id(el), ename, h]);
7099 E.on(el, ename, h); // this adds the actuall listener to the object..
7102 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7103 el.addEventListener("DOMMouseScroll", h, false);
7104 E.on(window, 'unload', function(){
7105 el.removeEventListener("DOMMouseScroll", h, false);
7108 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7109 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7114 var stopListening = function(el, ename, fn){
7115 var id = Roo.id(el), hds = fn._handlers, hd = fn;
7117 for(var i = 0, len = hds.length; i < len; i++){
7119 if(h[0] == id && h[1] == ename){
7126 E.un(el, ename, hd);
7127 el = Roo.getDom(el);
7128 if(ename == "mousewheel" && el.addEventListener){
7129 el.removeEventListener("DOMMouseScroll", hd, false);
7131 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7132 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7136 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7143 * @scope Roo.EventManager
7148 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7149 * object with a Roo.EventObject
7150 * @param {Function} fn The method the event invokes
7151 * @param {Object} scope An object that becomes the scope of the handler
7152 * @param {boolean} override If true, the obj passed in becomes
7153 * the execution scope of the listener
7154 * @return {Function} The wrapped function
7157 wrap : function(fn, scope, override){
7159 Roo.EventObject.setEvent(e);
7160 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7165 * Appends an event handler to an element (shorthand for addListener)
7166 * @param {String/HTMLElement} element The html element or id to assign the
7167 * @param {String} eventName The type of event to listen for
7168 * @param {Function} handler The method the event invokes
7169 * @param {Object} scope (optional) The scope in which to execute the handler
7170 * function. The handler function's "this" context.
7171 * @param {Object} options (optional) An object containing handler configuration
7172 * properties. This may contain any of the following properties:<ul>
7173 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7174 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7175 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7176 * <li>preventDefault {Boolean} True to prevent the default action</li>
7177 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7178 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7179 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7180 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7181 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7182 * by the specified number of milliseconds. If the event fires again within that time, the original
7183 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7186 * <b>Combining Options</b><br>
7187 * Using the options argument, it is possible to combine different types of listeners:<br>
7189 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7191 el.on('click', this.onClick, this, {
7198 * <b>Attaching multiple handlers in 1 call</b><br>
7199 * The method also allows for a single argument to be passed which is a config object containing properties
7200 * which specify multiple handlers.
7210 fn: this.onMouseOver
7219 * Or a shorthand syntax:<br>
7222 'click' : this.onClick,
7223 'mouseover' : this.onMouseOver,
7224 'mouseout' : this.onMouseOut
7228 addListener : function(element, eventName, fn, scope, options){
7229 if(typeof eventName == "object"){
7235 if(typeof o[e] == "function"){
7237 listen(element, e, o, o[e], o.scope);
7239 // individual options
7240 listen(element, e, o[e]);
7245 return listen(element, eventName, options, fn, scope);
7249 * Removes an event handler
7251 * @param {String/HTMLElement} element The id or html element to remove the
7253 * @param {String} eventName The type of event
7254 * @param {Function} fn
7255 * @return {Boolean} True if a listener was actually removed
7257 removeListener : function(element, eventName, fn){
7258 return stopListening(element, eventName, fn);
7262 * Fires when the document is ready (before onload and before images are loaded). Can be
7263 * accessed shorthanded Roo.onReady().
7264 * @param {Function} fn The method the event invokes
7265 * @param {Object} scope An object that becomes the scope of the handler
7266 * @param {boolean} options
7268 onDocumentReady : function(fn, scope, options){
7269 if(docReadyState){ // if it already fired
7270 docReadyEvent.addListener(fn, scope, options);
7271 docReadyEvent.fire();
7272 docReadyEvent.clearListeners();
7278 docReadyEvent.addListener(fn, scope, options);
7282 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7283 * @param {Function} fn The method the event invokes
7284 * @param {Object} scope An object that becomes the scope of the handler
7285 * @param {boolean} options
7287 onWindowResize : function(fn, scope, options)
7290 resizeEvent = new Roo.util.Event();
7291 resizeTask = new Roo.util.DelayedTask(function(){
7292 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7294 E.on(window, "resize", function()
7297 resizeTask.delay(50);
7299 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7303 resizeEvent.addListener(fn, scope, options);
7307 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7308 * @param {Function} fn The method the event invokes
7309 * @param {Object} scope An object that becomes the scope of the handler
7310 * @param {boolean} options
7312 onTextResize : function(fn, scope, options){
7314 textEvent = new Roo.util.Event();
7315 var textEl = new Roo.Element(document.createElement('div'));
7316 textEl.dom.className = 'x-text-resize';
7317 textEl.dom.innerHTML = 'X';
7318 textEl.appendTo(document.body);
7319 textSize = textEl.dom.offsetHeight;
7320 setInterval(function(){
7321 if(textEl.dom.offsetHeight != textSize){
7322 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7324 }, this.textResizeInterval);
7326 textEvent.addListener(fn, scope, options);
7330 * Removes the passed window resize listener.
7331 * @param {Function} fn The method the event invokes
7332 * @param {Object} scope The scope of handler
7334 removeResizeListener : function(fn, scope){
7336 resizeEvent.removeListener(fn, scope);
7341 fireResize : function(){
7343 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7347 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7351 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7353 textResizeInterval : 50
7358 * @scopeAlias pub=Roo.EventManager
7362 * Appends an event handler to an element (shorthand for addListener)
7363 * @param {String/HTMLElement} element The html element or id to assign the
7364 * @param {String} eventName The type of event to listen for
7365 * @param {Function} handler The method the event invokes
7366 * @param {Object} scope (optional) The scope in which to execute the handler
7367 * function. The handler function's "this" context.
7368 * @param {Object} options (optional) An object containing handler configuration
7369 * properties. This may contain any of the following properties:<ul>
7370 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7371 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7372 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7373 * <li>preventDefault {Boolean} True to prevent the default action</li>
7374 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7375 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7376 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7377 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7378 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7379 * by the specified number of milliseconds. If the event fires again within that time, the original
7380 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7383 * <b>Combining Options</b><br>
7384 * Using the options argument, it is possible to combine different types of listeners:<br>
7386 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7388 el.on('click', this.onClick, this, {
7395 * <b>Attaching multiple handlers in 1 call</b><br>
7396 * The method also allows for a single argument to be passed which is a config object containing properties
7397 * which specify multiple handlers.
7407 fn: this.onMouseOver
7416 * Or a shorthand syntax:<br>
7419 'click' : this.onClick,
7420 'mouseover' : this.onMouseOver,
7421 'mouseout' : this.onMouseOut
7425 pub.on = pub.addListener;
7426 pub.un = pub.removeListener;
7428 pub.stoppedMouseDownEvent = new Roo.util.Event();
7432 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
7433 * @param {Function} fn The method the event invokes
7434 * @param {Object} scope An object that becomes the scope of the handler
7435 * @param {boolean} override If true, the obj passed in becomes
7436 * the execution scope of the listener
7440 Roo.onReady = Roo.EventManager.onDocumentReady;
7442 Roo.onReady(function(){
7443 var bd = Roo.get(document.body);
7448 : Roo.isIE11 ? "roo-ie11"
7449 : Roo.isEdge ? "roo-edge"
7450 : Roo.isGecko ? "roo-gecko"
7451 : Roo.isOpera ? "roo-opera"
7452 : Roo.isSafari ? "roo-safari" : ""];
7455 cls.push("roo-mac");
7458 cls.push("roo-linux");
7461 cls.push("roo-ios");
7464 cls.push("roo-touch");
7466 if(Roo.isBorderBox){
7467 cls.push('roo-border-box');
7469 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7470 var p = bd.dom.parentNode;
7472 p.className += ' roo-strict';
7475 bd.addClass(cls.join(' '));
7479 * @class Roo.EventObject
7480 * EventObject exposes the Yahoo! UI Event functionality directly on the object
7481 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
7484 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7486 var target = e.getTarget();
7489 var myDiv = Roo.get("myDiv");
7490 myDiv.on("click", handleClick);
7492 Roo.EventManager.on("myDiv", 'click', handleClick);
7493 Roo.EventManager.addListener("myDiv", 'click', handleClick);
7497 Roo.EventObject = function(){
7499 var E = Roo.lib.Event;
7501 // safari keypress events for special keys return bad keycodes
7504 63235 : 39, // right
7507 63276 : 33, // page up
7508 63277 : 34, // page down
7509 63272 : 46, // delete
7514 // normalize button clicks
7515 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7516 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7518 Roo.EventObjectImpl = function(e){
7520 this.setEvent(e.browserEvent || e);
7523 Roo.EventObjectImpl.prototype = {
7525 * Used to fix doc tools.
7526 * @scope Roo.EventObject.prototype
7532 /** The normal browser event */
7533 browserEvent : null,
7534 /** The button pressed in a mouse event */
7536 /** True if the shift key was down during the event */
7538 /** True if the control key was down during the event */
7540 /** True if the alt key was down during the event */
7599 setEvent : function(e){
7600 if(e == this || (e && e.browserEvent)){ // already wrapped
7603 this.browserEvent = e;
7605 // normalize buttons
7606 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
7607 if(e.type == 'click' && this.button == -1){
7611 this.shiftKey = e.shiftKey;
7612 // mac metaKey behaves like ctrlKey
7613 this.ctrlKey = e.ctrlKey || e.metaKey;
7614 this.altKey = e.altKey;
7615 // in getKey these will be normalized for the mac
7616 this.keyCode = e.keyCode;
7617 // keyup warnings on firefox.
7618 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
7619 // cache the target for the delayed and or buffered events
7620 this.target = E.getTarget(e);
7622 this.xy = E.getXY(e);
7625 this.shiftKey = false;
7626 this.ctrlKey = false;
7627 this.altKey = false;
7637 * Stop the event (preventDefault and stopPropagation)
7639 stopEvent : function(){
7640 if(this.browserEvent){
7641 if(this.browserEvent.type == 'mousedown'){
7642 Roo.EventManager.stoppedMouseDownEvent.fire(this);
7644 E.stopEvent(this.browserEvent);
7649 * Prevents the browsers default handling of the event.
7651 preventDefault : function(){
7652 if(this.browserEvent){
7653 E.preventDefault(this.browserEvent);
7658 isNavKeyPress : function(){
7659 var k = this.keyCode;
7660 k = Roo.isSafari ? (safariKeys[k] || k) : k;
7661 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
7664 isSpecialKey : function(){
7665 var k = this.keyCode;
7666 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
7667 (k == 16) || (k == 17) ||
7668 (k >= 18 && k <= 20) ||
7669 (k >= 33 && k <= 35) ||
7670 (k >= 36 && k <= 39) ||
7671 (k >= 44 && k <= 45);
7674 * Cancels bubbling of the event.
7676 stopPropagation : function(){
7677 if(this.browserEvent){
7678 if(this.type == 'mousedown'){
7679 Roo.EventManager.stoppedMouseDownEvent.fire(this);
7681 E.stopPropagation(this.browserEvent);
7686 * Gets the key code for the event.
7689 getCharCode : function(){
7690 return this.charCode || this.keyCode;
7694 * Returns a normalized keyCode for the event.
7695 * @return {Number} The key code
7697 getKey : function(){
7698 var k = this.keyCode || this.charCode;
7699 return Roo.isSafari ? (safariKeys[k] || k) : k;
7703 * Gets the x coordinate of the event.
7706 getPageX : function(){
7711 * Gets the y coordinate of the event.
7714 getPageY : function(){
7719 * Gets the time of the event.
7722 getTime : function(){
7723 if(this.browserEvent){
7724 return E.getTime(this.browserEvent);
7730 * Gets the page coordinates of the event.
7731 * @return {Array} The xy values like [x, y]
7738 * Gets the target for the event.
7739 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7740 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7741 search as a number or element (defaults to 10 || document.body)
7742 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7743 * @return {HTMLelement}
7745 getTarget : function(selector, maxDepth, returnEl){
7746 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7749 * Gets the related target.
7750 * @return {HTMLElement}
7752 getRelatedTarget : function(){
7753 if(this.browserEvent){
7754 return E.getRelatedTarget(this.browserEvent);
7760 * Normalizes mouse wheel delta across browsers
7761 * @return {Number} The delta
7763 getWheelDelta : function(){
7764 var e = this.browserEvent;
7766 if(e.wheelDelta){ /* IE/Opera. */
7767 delta = e.wheelDelta/120;
7768 }else if(e.detail){ /* Mozilla case. */
7769 delta = -e.detail/3;
7775 * Returns true if the control, meta, shift or alt key was pressed during this event.
7778 hasModifier : function(){
7779 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7783 * Returns true if the target of this event equals el or is a child of el
7784 * @param {String/HTMLElement/Element} el
7785 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7788 within : function(el, related){
7789 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7790 return t && Roo.fly(el).contains(t);
7793 getPoint : function(){
7794 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7798 return new Roo.EventObjectImpl();
7803 * Ext JS Library 1.1.1
7804 * Copyright(c) 2006-2007, Ext JS, LLC.
7806 * Originally Released Under LGPL - original licence link has changed is not relivant.
7809 * <script type="text/javascript">
7813 // was in Composite Element!??!?!
7816 var D = Roo.lib.Dom;
7817 var E = Roo.lib.Event;
7818 var A = Roo.lib.Anim;
7820 // local style camelizing for speed
7822 var camelRe = /(-[a-z])/gi;
7823 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7824 var view = document.defaultView;
7827 * @class Roo.Element
7828 * Represents an Element in the DOM.<br><br>
7831 var el = Roo.get("my-div");
7834 var el = getEl("my-div");
7836 // or with a DOM element
7837 var el = Roo.get(myDivElement);
7839 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7840 * each call instead of constructing a new one.<br><br>
7841 * <b>Animations</b><br />
7842 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7843 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7845 Option Default Description
7846 --------- -------- ---------------------------------------------
7847 duration .35 The duration of the animation in seconds
7848 easing easeOut The YUI easing method
7849 callback none A function to execute when the anim completes
7850 scope this The scope (this) of the callback function
7852 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7853 * manipulate the animation. Here's an example:
7855 var el = Roo.get("my-div");
7860 // default animation
7861 el.setWidth(100, true);
7863 // animation with some options set
7870 // using the "anim" property to get the Anim object
7876 el.setWidth(100, opt);
7878 if(opt.anim.isAnimated()){
7882 * <b> Composite (Collections of) Elements</b><br />
7883 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7884 * @constructor Create a new Element directly.
7885 * @param {String/HTMLElement} element
7886 * @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).
7888 Roo.Element = function(element, forceNew)
7890 var dom = typeof element == "string" ?
7891 document.getElementById(element) : element;
7893 this.listeners = {};
7895 if(!dom){ // invalid id/element
7899 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7900 return Roo.Element.cache[id];
7910 * The DOM element ID
7913 this.id = id || Roo.id(dom);
7915 return this; // assumed for cctor?
7918 var El = Roo.Element;
7922 * The element's default display mode (defaults to "")
7925 originalDisplay : "",
7928 // note this is overridden in BS version..
7931 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7937 * Sets the element's visibility mode. When setVisible() is called it
7938 * will use this to determine whether to set the visibility or the display property.
7939 * @param visMode Element.VISIBILITY or Element.DISPLAY
7940 * @return {Roo.Element} this
7942 setVisibilityMode : function(visMode){
7943 this.visibilityMode = visMode;
7947 * Convenience method for setVisibilityMode(Element.DISPLAY)
7948 * @param {String} display (optional) What to set display to when visible
7949 * @return {Roo.Element} this
7951 enableDisplayMode : function(display){
7952 this.setVisibilityMode(El.DISPLAY);
7953 if(typeof display != "undefined") { this.originalDisplay = display; }
7958 * 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)
7959 * @param {String} selector The simple selector to test
7960 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7961 search as a number or element (defaults to 10 || document.body)
7962 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7963 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7965 findParent : function(simpleSelector, maxDepth, returnEl){
7966 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7967 maxDepth = maxDepth || 50;
7968 if(typeof maxDepth != "number"){
7969 stopEl = Roo.getDom(maxDepth);
7972 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7973 if(dq.is(p, simpleSelector)){
7974 return returnEl ? Roo.get(p) : p;
7984 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7985 * @param {String} selector The simple selector to test
7986 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7987 search as a number or element (defaults to 10 || document.body)
7988 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7989 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7991 findParentNode : function(simpleSelector, maxDepth, returnEl){
7992 var p = Roo.fly(this.dom.parentNode, '_internal');
7993 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7997 * Looks at the scrollable parent element
7999 findScrollableParent : function()
8001 var overflowRegex = /(auto|scroll)/;
8003 if(this.getStyle('position') === 'fixed'){
8004 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8007 var excludeStaticParent = this.getStyle('position') === "absolute";
8009 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8011 if (excludeStaticParent && parent.getStyle('position') === "static") {
8015 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8019 if(parent.dom.nodeName.toLowerCase() == 'body'){
8020 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8024 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8028 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8029 * This is a shortcut for findParentNode() that always returns an Roo.Element.
8030 * @param {String} selector The simple selector to test
8031 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8032 search as a number or element (defaults to 10 || document.body)
8033 * @return {Roo.Element} The matching DOM node (or null if no match was found)
8035 up : function(simpleSelector, maxDepth){
8036 return this.findParentNode(simpleSelector, maxDepth, true);
8042 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8043 * @param {String} selector The simple selector to test
8044 * @return {Boolean} True if this element matches the selector, else false
8046 is : function(simpleSelector){
8047 return Roo.DomQuery.is(this.dom, simpleSelector);
8051 * Perform animation on this element.
8052 * @param {Object} args The YUI animation control args
8053 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8054 * @param {Function} onComplete (optional) Function to call when animation completes
8055 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8056 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8057 * @return {Roo.Element} this
8059 animate : function(args, duration, onComplete, easing, animType){
8060 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8065 * @private Internal animation call
8067 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8068 animType = animType || 'run';
8070 var anim = Roo.lib.Anim[animType](
8072 (opt.duration || defaultDur) || .35,
8073 (opt.easing || defaultEase) || 'easeOut',
8075 Roo.callback(cb, this);
8076 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8084 // private legacy anim prep
8085 preanim : function(a, i){
8086 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8090 * Removes worthless text nodes
8091 * @param {Boolean} forceReclean (optional) By default the element
8092 * keeps track if it has been cleaned already so
8093 * you can call this over and over. However, if you update the element and
8094 * need to force a reclean, you can pass true.
8096 clean : function(forceReclean){
8097 if(this.isCleaned && forceReclean !== true){
8101 var d = this.dom, n = d.firstChild, ni = -1;
8103 var nx = n.nextSibling;
8104 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8111 this.isCleaned = true;
8116 calcOffsetsTo : function(el){
8119 var restorePos = false;
8120 if(el.getStyle('position') == 'static'){
8121 el.position('relative');
8126 while(op && op != d && op.tagName != 'HTML'){
8129 op = op.offsetParent;
8132 el.position('static');
8138 * Scrolls this element into view within the passed container.
8139 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8140 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8141 * @return {Roo.Element} this
8143 scrollIntoView : function(container, hscroll){
8144 var c = Roo.getDom(container) || document.body;
8147 var o = this.calcOffsetsTo(c),
8150 b = t+el.offsetHeight,
8151 r = l+el.offsetWidth;
8153 var ch = c.clientHeight;
8154 var ct = parseInt(c.scrollTop, 10);
8155 var cl = parseInt(c.scrollLeft, 10);
8157 var cr = cl + c.clientWidth;
8165 if(hscroll !== false){
8169 c.scrollLeft = r-c.clientWidth;
8176 scrollChildIntoView : function(child, hscroll){
8177 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8181 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8182 * the new height may not be available immediately.
8183 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8184 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8185 * @param {Function} onComplete (optional) Function to call when animation completes
8186 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8187 * @return {Roo.Element} this
8189 autoHeight : function(animate, duration, onComplete, easing){
8190 var oldHeight = this.getHeight();
8192 this.setHeight(1); // force clipping
8193 setTimeout(function(){
8194 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8196 this.setHeight(height);
8198 if(typeof onComplete == "function"){
8202 this.setHeight(oldHeight); // restore original height
8203 this.setHeight(height, animate, duration, function(){
8205 if(typeof onComplete == "function") { onComplete(); }
8206 }.createDelegate(this), easing);
8208 }.createDelegate(this), 0);
8213 * Returns true if this element is an ancestor of the passed element
8214 * @param {HTMLElement/String} el The element to check
8215 * @return {Boolean} True if this element is an ancestor of el, else false
8217 contains : function(el){
8218 if(!el){return false;}
8219 return D.isAncestor(this.dom, el.dom ? el.dom : el);
8223 * Checks whether the element is currently visible using both visibility and display properties.
8224 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8225 * @return {Boolean} True if the element is currently visible, else false
8227 isVisible : function(deep) {
8228 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8229 if(deep !== true || !vis){
8232 var p = this.dom.parentNode;
8233 while(p && p.tagName.toLowerCase() != "body"){
8234 if(!Roo.fly(p, '_isVisible').isVisible()){
8243 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8244 * @param {String} selector The CSS selector
8245 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8246 * @return {CompositeElement/CompositeElementLite} The composite element
8248 select : function(selector, unique){
8249 return El.select(selector, unique, this.dom);
8253 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8254 * @param {String} selector The CSS selector
8255 * @return {Array} An array of the matched nodes
8257 query : function(selector, unique){
8258 return Roo.DomQuery.select(selector, this.dom);
8262 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8263 * @param {String} selector The CSS selector
8264 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8265 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8267 child : function(selector, returnDom){
8268 var n = Roo.DomQuery.selectNode(selector, this.dom);
8269 return returnDom ? n : Roo.get(n);
8273 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8274 * @param {String} selector The CSS selector
8275 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8276 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8278 down : function(selector, returnDom){
8279 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8280 return returnDom ? n : Roo.get(n);
8284 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8285 * @param {String} group The group the DD object is member of
8286 * @param {Object} config The DD config object
8287 * @param {Object} overrides An object containing methods to override/implement on the DD object
8288 * @return {Roo.dd.DD} The DD object
8290 initDD : function(group, config, overrides){
8291 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8292 return Roo.apply(dd, overrides);
8296 * Initializes a {@link Roo.dd.DDProxy} object for this element.
8297 * @param {String} group The group the DDProxy object is member of
8298 * @param {Object} config The DDProxy config object
8299 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8300 * @return {Roo.dd.DDProxy} The DDProxy object
8302 initDDProxy : function(group, config, overrides){
8303 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8304 return Roo.apply(dd, overrides);
8308 * Initializes a {@link Roo.dd.DDTarget} object for this element.
8309 * @param {String} group The group the DDTarget object is member of
8310 * @param {Object} config The DDTarget config object
8311 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8312 * @return {Roo.dd.DDTarget} The DDTarget object
8314 initDDTarget : function(group, config, overrides){
8315 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8316 return Roo.apply(dd, overrides);
8320 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8321 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8322 * @param {Boolean} visible Whether the element is visible
8323 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8324 * @return {Roo.Element} this
8326 setVisible : function(visible, animate){
8328 if(this.visibilityMode == El.DISPLAY){
8329 this.setDisplayed(visible);
8332 this.dom.style.visibility = visible ? "visible" : "hidden";
8335 // closure for composites
8337 var visMode = this.visibilityMode;
8339 this.setOpacity(.01);
8340 this.setVisible(true);
8342 this.anim({opacity: { to: (visible?1:0) }},
8343 this.preanim(arguments, 1),
8344 null, .35, 'easeIn', function(){
8346 if(visMode == El.DISPLAY){
8347 dom.style.display = "none";
8349 dom.style.visibility = "hidden";
8351 Roo.get(dom).setOpacity(1);
8359 * Returns true if display is not "none"
8362 isDisplayed : function() {
8363 return this.getStyle("display") != "none";
8367 * Toggles the element's visibility or display, depending on visibility mode.
8368 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8369 * @return {Roo.Element} this
8371 toggle : function(animate){
8372 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8377 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8378 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8379 * @return {Roo.Element} this
8381 setDisplayed : function(value) {
8382 if(typeof value == "boolean"){
8383 value = value ? this.originalDisplay : "none";
8385 this.setStyle("display", value);
8390 * Tries to focus the element. Any exceptions are caught and ignored.
8391 * @return {Roo.Element} this
8393 focus : function() {
8401 * Tries to blur the element. Any exceptions are caught and ignored.
8402 * @return {Roo.Element} this
8412 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8413 * @param {String/Array} className The CSS class to add, or an array of classes
8414 * @return {Roo.Element} this
8416 addClass : function(className){
8417 if(className instanceof Array){
8418 for(var i = 0, len = className.length; i < len; i++) {
8419 this.addClass(className[i]);
8422 if(className && !this.hasClass(className)){
8423 if (this.dom instanceof SVGElement) {
8424 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
8426 this.dom.className = this.dom.className + " " + className;
8434 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8435 * @param {String/Array} className The CSS class to add, or an array of classes
8436 * @return {Roo.Element} this
8438 radioClass : function(className){
8439 var siblings = this.dom.parentNode.childNodes;
8440 for(var i = 0; i < siblings.length; i++) {
8441 var s = siblings[i];
8442 if(s.nodeType == 1){
8443 Roo.get(s).removeClass(className);
8446 this.addClass(className);
8451 * Removes one or more CSS classes from the element.
8452 * @param {String/Array} className The CSS class to remove, or an array of classes
8453 * @return {Roo.Element} this
8455 removeClass : function(className){
8457 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8458 if(!className || !cn){
8461 if(className instanceof Array){
8462 for(var i = 0, len = className.length; i < len; i++) {
8463 this.removeClass(className[i]);
8466 if(this.hasClass(className)){
8467 var re = this.classReCache[className];
8469 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8470 this.classReCache[className] = re;
8472 if (this.dom instanceof SVGElement) {
8473 this.dom.className.baseVal = cn.replace(re, " ");
8475 this.dom.className = cn.replace(re, " ");
8486 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8487 * @param {String} className The CSS class to toggle
8488 * @return {Roo.Element} this
8490 toggleClass : function(className){
8491 if(this.hasClass(className)){
8492 this.removeClass(className);
8494 this.addClass(className);
8500 * Checks if the specified CSS class exists on this element's DOM node.
8501 * @param {String} className The CSS class to check for
8502 * @return {Boolean} True if the class exists, else false
8504 hasClass : function(className){
8505 if (this.dom instanceof SVGElement) {
8506 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
8508 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8512 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
8513 * @param {String} oldClassName The CSS class to replace
8514 * @param {String} newClassName The replacement CSS class
8515 * @return {Roo.Element} this
8517 replaceClass : function(oldClassName, newClassName){
8518 this.removeClass(oldClassName);
8519 this.addClass(newClassName);
8524 * Returns an object with properties matching the styles requested.
8525 * For example, el.getStyles('color', 'font-size', 'width') might return
8526 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8527 * @param {String} style1 A style name
8528 * @param {String} style2 A style name
8529 * @param {String} etc.
8530 * @return {Object} The style object
8532 getStyles : function(){
8533 var a = arguments, len = a.length, r = {};
8534 for(var i = 0; i < len; i++){
8535 r[a[i]] = this.getStyle(a[i]);
8541 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8542 * @param {String} property The style property whose value is returned.
8543 * @return {String} The current value of the style property for this element.
8545 getStyle : function(){
8546 return view && view.getComputedStyle ?
8548 var el = this.dom, v, cs, camel;
8549 if(prop == 'float'){
8552 if(el.style && (v = el.style[prop])){
8555 if(cs = view.getComputedStyle(el, "")){
8556 if(!(camel = propCache[prop])){
8557 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8564 var el = this.dom, v, cs, camel;
8565 if(prop == 'opacity'){
8566 if(typeof el.style.filter == 'string'){
8567 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8569 var fv = parseFloat(m[1]);
8571 return fv ? fv / 100 : 0;
8576 }else if(prop == 'float'){
8577 prop = "styleFloat";
8579 if(!(camel = propCache[prop])){
8580 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8582 if(v = el.style[camel]){
8585 if(cs = el.currentStyle){
8593 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8594 * @param {String/Object} property The style property to be set, or an object of multiple styles.
8595 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8596 * @return {Roo.Element} this
8598 setStyle : function(prop, value){
8599 if(typeof prop == "string"){
8601 if (prop == 'float') {
8602 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
8607 if(!(camel = propCache[prop])){
8608 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8611 if(camel == 'opacity') {
8612 this.setOpacity(value);
8614 this.dom.style[camel] = value;
8617 for(var style in prop){
8618 if(typeof prop[style] != "function"){
8619 this.setStyle(style, prop[style]);
8627 * More flexible version of {@link #setStyle} for setting style properties.
8628 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
8629 * a function which returns such a specification.
8630 * @return {Roo.Element} this
8632 applyStyles : function(style){
8633 Roo.DomHelper.applyStyles(this.dom, style);
8638 * 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).
8639 * @return {Number} The X position of the element
8642 return D.getX(this.dom);
8646 * 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).
8647 * @return {Number} The Y position of the element
8650 return D.getY(this.dom);
8654 * 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).
8655 * @return {Array} The XY position of the element
8658 return D.getXY(this.dom);
8662 * 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).
8663 * @param {Number} The X position of the element
8664 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8665 * @return {Roo.Element} this
8667 setX : function(x, animate){
8669 D.setX(this.dom, x);
8671 this.setXY([x, this.getY()], this.preanim(arguments, 1));
8677 * 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).
8678 * @param {Number} The Y position of the element
8679 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8680 * @return {Roo.Element} this
8682 setY : function(y, animate){
8684 D.setY(this.dom, y);
8686 this.setXY([this.getX(), y], this.preanim(arguments, 1));
8692 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8693 * @param {String} left The left CSS property value
8694 * @return {Roo.Element} this
8696 setLeft : function(left){
8697 this.setStyle("left", this.addUnits(left));
8702 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8703 * @param {String} top The top CSS property value
8704 * @return {Roo.Element} this
8706 setTop : function(top){
8707 this.setStyle("top", this.addUnits(top));
8712 * Sets the element's CSS right style.
8713 * @param {String} right The right CSS property value
8714 * @return {Roo.Element} this
8716 setRight : function(right){
8717 this.setStyle("right", this.addUnits(right));
8722 * Sets the element's CSS bottom style.
8723 * @param {String} bottom The bottom CSS property value
8724 * @return {Roo.Element} this
8726 setBottom : function(bottom){
8727 this.setStyle("bottom", this.addUnits(bottom));
8732 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8733 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8734 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8735 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8736 * @return {Roo.Element} this
8738 setXY : function(pos, animate){
8740 D.setXY(this.dom, pos);
8742 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8748 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8749 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8750 * @param {Number} x X value for new position (coordinates are page-based)
8751 * @param {Number} y Y value for new position (coordinates are page-based)
8752 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8753 * @return {Roo.Element} this
8755 setLocation : function(x, y, animate){
8756 this.setXY([x, y], this.preanim(arguments, 2));
8761 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8762 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8763 * @param {Number} x X value for new position (coordinates are page-based)
8764 * @param {Number} y Y value for new position (coordinates are page-based)
8765 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8766 * @return {Roo.Element} this
8768 moveTo : function(x, y, animate){
8769 this.setXY([x, y], this.preanim(arguments, 2));
8774 * Returns the region of the given element.
8775 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8776 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8778 getRegion : function(){
8779 return D.getRegion(this.dom);
8783 * Returns the offset height of the element
8784 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8785 * @return {Number} The element's height
8787 getHeight : function(contentHeight){
8788 var h = this.dom.offsetHeight || 0;
8789 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8793 * Returns the offset width of the element
8794 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8795 * @return {Number} The element's width
8797 getWidth : function(contentWidth){
8798 var w = this.dom.offsetWidth || 0;
8799 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8803 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8804 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8805 * if a height has not been set using CSS.
8808 getComputedHeight : function(){
8809 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8811 h = parseInt(this.getStyle('height'), 10) || 0;
8812 if(!this.isBorderBox()){
8813 h += this.getFrameWidth('tb');
8820 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8821 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8822 * if a width has not been set using CSS.
8825 getComputedWidth : function(){
8826 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8828 w = parseInt(this.getStyle('width'), 10) || 0;
8829 if(!this.isBorderBox()){
8830 w += this.getFrameWidth('lr');
8837 * Returns the size of the element.
8838 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8839 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8841 getSize : function(contentSize){
8842 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8846 * Returns the width and height of the viewport.
8847 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8849 getViewSize : function(){
8850 var d = this.dom, doc = document, aw = 0, ah = 0;
8851 if(d == doc || d == doc.body){
8852 return {width : D.getViewWidth(), height: D.getViewHeight()};
8855 width : d.clientWidth,
8856 height: d.clientHeight
8862 * Returns the value of the "value" attribute
8863 * @param {Boolean} asNumber true to parse the value as a number
8864 * @return {String/Number}
8866 getValue : function(asNumber){
8867 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8871 adjustWidth : function(width){
8872 if(typeof width == "number"){
8873 if(this.autoBoxAdjust && !this.isBorderBox()){
8874 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8884 adjustHeight : function(height){
8885 if(typeof height == "number"){
8886 if(this.autoBoxAdjust && !this.isBorderBox()){
8887 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8897 * Set the width of the element
8898 * @param {Number} width The new width
8899 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8900 * @return {Roo.Element} this
8902 setWidth : function(width, animate){
8903 width = this.adjustWidth(width);
8905 this.dom.style.width = this.addUnits(width);
8907 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8913 * Set the height of the element
8914 * @param {Number} height The new height
8915 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8916 * @return {Roo.Element} this
8918 setHeight : function(height, animate){
8919 height = this.adjustHeight(height);
8921 this.dom.style.height = this.addUnits(height);
8923 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8929 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8930 * @param {Number} width The new width
8931 * @param {Number} height The new height
8932 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8933 * @return {Roo.Element} this
8935 setSize : function(width, height, animate){
8936 if(typeof width == "object"){ // in case of object from getSize()
8937 height = width.height; width = width.width;
8939 width = this.adjustWidth(width); height = this.adjustHeight(height);
8941 this.dom.style.width = this.addUnits(width);
8942 this.dom.style.height = this.addUnits(height);
8944 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8950 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8951 * @param {Number} x X value for new position (coordinates are page-based)
8952 * @param {Number} y Y value for new position (coordinates are page-based)
8953 * @param {Number} width The new width
8954 * @param {Number} height The new height
8955 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8956 * @return {Roo.Element} this
8958 setBounds : function(x, y, width, height, animate){
8960 this.setSize(width, height);
8961 this.setLocation(x, y);
8963 width = this.adjustWidth(width); height = this.adjustHeight(height);
8964 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8965 this.preanim(arguments, 4), 'motion');
8971 * 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.
8972 * @param {Roo.lib.Region} region The region to fill
8973 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8974 * @return {Roo.Element} this
8976 setRegion : function(region, animate){
8977 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8982 * Appends an event handler
8984 * @param {String} eventName The type of event to append
8985 * @param {Function} fn The method the event invokes
8986 * @param {Object} scope (optional) The scope (this object) of the fn
8987 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8989 addListener : function(eventName, fn, scope, options)
8991 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
8992 this.addListener('touchstart', this.onTapHandler, this);
8995 // we need to handle a special case where dom element is a svg element.
8996 // in this case we do not actua
9001 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9002 if (typeof(this.listeners[eventName]) == 'undefined') {
9003 this.listeners[eventName] = new Roo.util.Event(this, eventName);
9005 this.listeners[eventName].addListener(fn, scope, options);
9010 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
9015 onTapHandler : function(event)
9017 if(!this.tapedTwice) {
9018 this.tapedTwice = true;
9020 setTimeout( function() {
9021 s.tapedTwice = false;
9025 event.preventDefault();
9026 var revent = new MouseEvent('dblclick', {
9032 this.dom.dispatchEvent(revent);
9033 //action on double tap goes below
9038 * Removes an event handler from this element
9039 * @param {String} eventName the type of event to remove
9040 * @param {Function} fn the method the event invokes
9041 * @param {Function} scope (needed for svg fake listeners)
9042 * @return {Roo.Element} this
9044 removeListener : function(eventName, fn, scope){
9045 Roo.EventManager.removeListener(this.dom, eventName, fn);
9046 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
9049 this.listeners[eventName].removeListener(fn, scope);
9054 * Removes all previous added listeners from this element
9055 * @return {Roo.Element} this
9057 removeAllListeners : function(){
9058 E.purgeElement(this.dom);
9059 this.listeners = {};
9063 relayEvent : function(eventName, observable){
9064 this.on(eventName, function(e){
9065 observable.fireEvent(eventName, e);
9071 * Set the opacity of the element
9072 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9073 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9074 * @return {Roo.Element} this
9076 setOpacity : function(opacity, animate){
9078 var s = this.dom.style;
9081 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9082 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9084 s.opacity = opacity;
9087 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9093 * Gets the left X coordinate
9094 * @param {Boolean} local True to get the local css position instead of page coordinate
9097 getLeft : function(local){
9101 return parseInt(this.getStyle("left"), 10) || 0;
9106 * Gets the right X coordinate of the element (element X position + element width)
9107 * @param {Boolean} local True to get the local css position instead of page coordinate
9110 getRight : function(local){
9112 return this.getX() + this.getWidth();
9114 return (this.getLeft(true) + this.getWidth()) || 0;
9119 * Gets the top Y coordinate
9120 * @param {Boolean} local True to get the local css position instead of page coordinate
9123 getTop : function(local) {
9127 return parseInt(this.getStyle("top"), 10) || 0;
9132 * Gets the bottom Y coordinate of the element (element Y position + element height)
9133 * @param {Boolean} local True to get the local css position instead of page coordinate
9136 getBottom : function(local){
9138 return this.getY() + this.getHeight();
9140 return (this.getTop(true) + this.getHeight()) || 0;
9145 * Initializes positioning on this element. If a desired position is not passed, it will make the
9146 * the element positioned relative IF it is not already positioned.
9147 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9148 * @param {Number} zIndex (optional) The zIndex to apply
9149 * @param {Number} x (optional) Set the page X position
9150 * @param {Number} y (optional) Set the page Y position
9152 position : function(pos, zIndex, x, y){
9154 if(this.getStyle('position') == 'static'){
9155 this.setStyle('position', 'relative');
9158 this.setStyle("position", pos);
9161 this.setStyle("z-index", zIndex);
9163 if(x !== undefined && y !== undefined){
9165 }else if(x !== undefined){
9167 }else if(y !== undefined){
9173 * Clear positioning back to the default when the document was loaded
9174 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9175 * @return {Roo.Element} this
9177 clearPositioning : function(value){
9185 "position" : "static"
9191 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9192 * snapshot before performing an update and then restoring the element.
9195 getPositioning : function(){
9196 var l = this.getStyle("left");
9197 var t = this.getStyle("top");
9199 "position" : this.getStyle("position"),
9201 "right" : l ? "" : this.getStyle("right"),
9203 "bottom" : t ? "" : this.getStyle("bottom"),
9204 "z-index" : this.getStyle("z-index")
9209 * Gets the width of the border(s) for the specified side(s)
9210 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9211 * passing lr would get the border (l)eft width + the border (r)ight width.
9212 * @return {Number} The width of the sides passed added together
9214 getBorderWidth : function(side){
9215 return this.addStyles(side, El.borders);
9219 * Gets the width of the padding(s) for the specified side(s)
9220 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9221 * passing lr would get the padding (l)eft + the padding (r)ight.
9222 * @return {Number} The padding of the sides passed added together
9224 getPadding : function(side){
9225 return this.addStyles(side, El.paddings);
9229 * Set positioning with an object returned by getPositioning().
9230 * @param {Object} posCfg
9231 * @return {Roo.Element} this
9233 setPositioning : function(pc){
9234 this.applyStyles(pc);
9235 if(pc.right == "auto"){
9236 this.dom.style.right = "";
9238 if(pc.bottom == "auto"){
9239 this.dom.style.bottom = "";
9245 fixDisplay : function(){
9246 if(this.getStyle("display") == "none"){
9247 this.setStyle("visibility", "hidden");
9248 this.setStyle("display", this.originalDisplay); // first try reverting to default
9249 if(this.getStyle("display") == "none"){ // if that fails, default to block
9250 this.setStyle("display", "block");
9256 * Quick set left and top adding default units
9257 * @param {String} left The left CSS property value
9258 * @param {String} top The top CSS property value
9259 * @return {Roo.Element} this
9261 setLeftTop : function(left, top){
9262 this.dom.style.left = this.addUnits(left);
9263 this.dom.style.top = this.addUnits(top);
9268 * Move this element relative to its current position.
9269 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9270 * @param {Number} distance How far to move the element in pixels
9271 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9272 * @return {Roo.Element} this
9274 move : function(direction, distance, animate){
9275 var xy = this.getXY();
9276 direction = direction.toLowerCase();
9280 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9284 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9289 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9294 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9301 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9302 * @return {Roo.Element} this
9305 if(!this.isClipped){
9306 this.isClipped = true;
9307 this.originalClip = {
9308 "o": this.getStyle("overflow"),
9309 "x": this.getStyle("overflow-x"),
9310 "y": this.getStyle("overflow-y")
9312 this.setStyle("overflow", "hidden");
9313 this.setStyle("overflow-x", "hidden");
9314 this.setStyle("overflow-y", "hidden");
9320 * Return clipping (overflow) to original clipping before clip() was called
9321 * @return {Roo.Element} this
9323 unclip : function(){
9325 this.isClipped = false;
9326 var o = this.originalClip;
9327 if(o.o){this.setStyle("overflow", o.o);}
9328 if(o.x){this.setStyle("overflow-x", o.x);}
9329 if(o.y){this.setStyle("overflow-y", o.y);}
9336 * Gets the x,y coordinates specified by the anchor position on the element.
9337 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
9338 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9339 * {width: (target width), height: (target height)} (defaults to the element's current size)
9340 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9341 * @return {Array} [x, y] An array containing the element's x and y coordinates
9343 getAnchorXY : function(anchor, local, s){
9344 //Passing a different size is useful for pre-calculating anchors,
9345 //especially for anchored animations that change the el size.
9347 var w, h, vp = false;
9350 if(d == document.body || d == document){
9352 w = D.getViewWidth(); h = D.getViewHeight();
9354 w = this.getWidth(); h = this.getHeight();
9357 w = s.width; h = s.height;
9359 var x = 0, y = 0, r = Math.round;
9360 switch((anchor || "tl").toLowerCase()){
9402 var sc = this.getScroll();
9403 return [x + sc.left, y + sc.top];
9405 //Add the element's offset xy
9406 var o = this.getXY();
9407 return [x+o[0], y+o[1]];
9411 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9412 * supported position values.
9413 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9414 * @param {String} position The position to align to.
9415 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9416 * @return {Array} [x, y]
9418 getAlignToXY : function(el, p, o)
9423 throw "Element.alignTo with an element that doesn't exist";
9425 var c = false; //constrain to viewport
9426 var p1 = "", p2 = "";
9433 }else if(p.indexOf("-") == -1){
9436 p = p.toLowerCase();
9437 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9439 throw "Element.alignTo with an invalid alignment " + p;
9441 p1 = m[1]; p2 = m[2]; c = !!m[3];
9443 //Subtract the aligned el's internal xy from the target's offset xy
9444 //plus custom offset to get the aligned el's new offset xy
9445 var a1 = this.getAnchorXY(p1, true);
9446 var a2 = el.getAnchorXY(p2, false);
9447 var x = a2[0] - a1[0] + o[0];
9448 var y = a2[1] - a1[1] + o[1];
9450 //constrain the aligned el to viewport if necessary
9451 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9452 // 5px of margin for ie
9453 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9455 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9456 //perpendicular to the vp border, allow the aligned el to slide on that border,
9457 //otherwise swap the aligned el to the opposite border of the target.
9458 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9459 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9460 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
9461 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9464 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9465 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9467 if((x+w) > dw + scrollX){
9468 x = swapX ? r.left-w : dw+scrollX-w;
9471 x = swapX ? r.right : scrollX;
9473 if((y+h) > dh + scrollY){
9474 y = swapY ? r.top-h : dh+scrollY-h;
9477 y = swapY ? r.bottom : scrollY;
9484 getConstrainToXY : function(){
9485 var os = {top:0, left:0, bottom:0, right: 0};
9487 return function(el, local, offsets, proposedXY){
9489 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9491 var vw, vh, vx = 0, vy = 0;
9492 if(el.dom == document.body || el.dom == document){
9493 vw = Roo.lib.Dom.getViewWidth();
9494 vh = Roo.lib.Dom.getViewHeight();
9496 vw = el.dom.clientWidth;
9497 vh = el.dom.clientHeight;
9499 var vxy = el.getXY();
9505 var s = el.getScroll();
9507 vx += offsets.left + s.left;
9508 vy += offsets.top + s.top;
9510 vw -= offsets.right;
9511 vh -= offsets.bottom;
9516 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9517 var x = xy[0], y = xy[1];
9518 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9520 // only move it if it needs it
9523 // first validate right/bottom
9532 // then make sure top/left isn't negative
9541 return moved ? [x, y] : false;
9546 adjustForConstraints : function(xy, parent, offsets){
9547 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
9551 * Aligns this element with another element relative to the specified anchor points. If the other element is the
9552 * document it aligns it to the viewport.
9553 * The position parameter is optional, and can be specified in any one of the following formats:
9555 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9556 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9557 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
9558 * deprecated in favor of the newer two anchor syntax below</i>.</li>
9559 * <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
9560 * element's anchor point, and the second value is used as the target's anchor point.</li>
9562 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
9563 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9564 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
9565 * that specified in order to enforce the viewport constraints.
9566 * Following are all of the supported anchor positions:
9569 ----- -----------------------------
9570 tl The top left corner (default)
9571 t The center of the top edge
9572 tr The top right corner
9573 l The center of the left edge
9574 c In the center of the element
9575 r The center of the right edge
9576 bl The bottom left corner
9577 b The center of the bottom edge
9578 br The bottom right corner
9582 // align el to other-el using the default positioning ("tl-bl", non-constrained)
9583 el.alignTo("other-el");
9585 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9586 el.alignTo("other-el", "tr?");
9588 // align the bottom right corner of el with the center left edge of other-el
9589 el.alignTo("other-el", "br-l?");
9591 // align the center of el with the bottom left corner of other-el and
9592 // adjust the x position by -6 pixels (and the y position by 0)
9593 el.alignTo("other-el", "c-bl", [-6, 0]);
9595 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9596 * @param {String} position The position to align to.
9597 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9598 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9599 * @return {Roo.Element} this
9601 alignTo : function(element, position, offsets, animate){
9602 var xy = this.getAlignToXY(element, position, offsets);
9603 this.setXY(xy, this.preanim(arguments, 3));
9608 * Anchors an element to another element and realigns it when the window is resized.
9609 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9610 * @param {String} position The position to align to.
9611 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9612 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
9613 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
9614 * is a number, it is used as the buffer delay (defaults to 50ms).
9615 * @param {Function} callback The function to call after the animation finishes
9616 * @return {Roo.Element} this
9618 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
9619 var action = function(){
9620 this.alignTo(el, alignment, offsets, animate);
9621 Roo.callback(callback, this);
9623 Roo.EventManager.onWindowResize(action, this);
9624 var tm = typeof monitorScroll;
9625 if(tm != 'undefined'){
9626 Roo.EventManager.on(window, 'scroll', action, this,
9627 {buffer: tm == 'number' ? monitorScroll : 50});
9629 action.call(this); // align immediately
9633 * Clears any opacity settings from this element. Required in some cases for IE.
9634 * @return {Roo.Element} this
9636 clearOpacity : function(){
9637 if (window.ActiveXObject) {
9638 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
9639 this.dom.style.filter = "";
9642 this.dom.style.opacity = "";
9643 this.dom.style["-moz-opacity"] = "";
9644 this.dom.style["-khtml-opacity"] = "";
9650 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9651 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9652 * @return {Roo.Element} this
9654 hide : function(animate){
9655 this.setVisible(false, this.preanim(arguments, 0));
9660 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9661 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9662 * @return {Roo.Element} this
9664 show : function(animate){
9665 this.setVisible(true, this.preanim(arguments, 0));
9670 * @private Test if size has a unit, otherwise appends the default
9672 addUnits : function(size){
9673 return Roo.Element.addUnits(size, this.defaultUnit);
9677 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
9678 * @return {Roo.Element} this
9680 beginMeasure : function(){
9682 if(el.offsetWidth || el.offsetHeight){
9683 return this; // offsets work already
9686 var p = this.dom, b = document.body; // start with this element
9687 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
9688 var pe = Roo.get(p);
9689 if(pe.getStyle('display') == 'none'){
9690 changed.push({el: p, visibility: pe.getStyle("visibility")});
9691 p.style.visibility = "hidden";
9692 p.style.display = "block";
9696 this._measureChanged = changed;
9702 * Restores displays to before beginMeasure was called
9703 * @return {Roo.Element} this
9705 endMeasure : function(){
9706 var changed = this._measureChanged;
9708 for(var i = 0, len = changed.length; i < len; i++) {
9710 r.el.style.visibility = r.visibility;
9711 r.el.style.display = "none";
9713 this._measureChanged = null;
9719 * Update the innerHTML of this element, optionally searching for and processing scripts
9720 * @param {String} html The new HTML
9721 * @param {Boolean} loadScripts (optional) true to look for and process scripts
9722 * @param {Function} callback For async script loading you can be noticed when the update completes
9723 * @return {Roo.Element} this
9725 update : function(html, loadScripts, callback){
9726 if(typeof html == "undefined"){
9729 if(loadScripts !== true){
9730 this.dom.innerHTML = html;
9731 if(typeof callback == "function"){
9739 html += '<span id="' + id + '"></span>';
9741 E.onAvailable(id, function(){
9742 var hd = document.getElementsByTagName("head")[0];
9743 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9744 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9745 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9748 while(match = re.exec(html)){
9749 var attrs = match[1];
9750 var srcMatch = attrs ? attrs.match(srcRe) : false;
9751 if(srcMatch && srcMatch[2]){
9752 var s = document.createElement("script");
9753 s.src = srcMatch[2];
9754 var typeMatch = attrs.match(typeRe);
9755 if(typeMatch && typeMatch[2]){
9756 s.type = typeMatch[2];
9759 }else if(match[2] && match[2].length > 0){
9760 if(window.execScript) {
9761 window.execScript(match[2]);
9769 window.eval(match[2]);
9773 var el = document.getElementById(id);
9774 if(el){el.parentNode.removeChild(el);}
9775 if(typeof callback == "function"){
9779 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9784 * Direct access to the UpdateManager update() method (takes the same parameters).
9785 * @param {String/Function} url The url for this request or a function to call to get the url
9786 * @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}
9787 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9788 * @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.
9789 * @return {Roo.Element} this
9792 var um = this.getUpdateManager();
9793 um.update.apply(um, arguments);
9798 * Gets this element's UpdateManager
9799 * @return {Roo.UpdateManager} The UpdateManager
9801 getUpdateManager : function(){
9802 if(!this.updateManager){
9803 this.updateManager = new Roo.UpdateManager(this);
9805 return this.updateManager;
9809 * Disables text selection for this element (normalized across browsers)
9810 * @return {Roo.Element} this
9812 unselectable : function(){
9813 this.dom.unselectable = "on";
9814 this.swallowEvent("selectstart", true);
9815 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9816 this.addClass("x-unselectable");
9821 * Calculates the x, y to center this element on the screen
9822 * @return {Array} The x, y values [x, y]
9824 getCenterXY : function(){
9825 return this.getAlignToXY(document, 'c-c');
9829 * Centers the Element in either the viewport, or another Element.
9830 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9832 center : function(centerIn){
9833 this.alignTo(centerIn || document, 'c-c');
9838 * Tests various css rules/browsers to determine if this element uses a border box
9841 isBorderBox : function(){
9842 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9846 * Return a box {x, y, width, height} that can be used to set another elements
9847 * size/location to match this element.
9848 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9849 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9850 * @return {Object} box An object in the format {x, y, width, height}
9852 getBox : function(contentBox, local){
9857 var left = parseInt(this.getStyle("left"), 10) || 0;
9858 var top = parseInt(this.getStyle("top"), 10) || 0;
9861 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9863 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9865 var l = this.getBorderWidth("l")+this.getPadding("l");
9866 var r = this.getBorderWidth("r")+this.getPadding("r");
9867 var t = this.getBorderWidth("t")+this.getPadding("t");
9868 var b = this.getBorderWidth("b")+this.getPadding("b");
9869 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)};
9871 bx.right = bx.x + bx.width;
9872 bx.bottom = bx.y + bx.height;
9877 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9878 for more information about the sides.
9879 * @param {String} sides
9882 getFrameWidth : function(sides, onlyContentBox){
9883 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9887 * 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.
9888 * @param {Object} box The box to fill {x, y, width, height}
9889 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9890 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9891 * @return {Roo.Element} this
9893 setBox : function(box, adjust, animate){
9894 var w = box.width, h = box.height;
9895 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9896 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9897 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9899 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9904 * Forces the browser to repaint this element
9905 * @return {Roo.Element} this
9907 repaint : function(){
9909 this.addClass("x-repaint");
9910 setTimeout(function(){
9911 Roo.get(dom).removeClass("x-repaint");
9917 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9918 * then it returns the calculated width of the sides (see getPadding)
9919 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9920 * @return {Object/Number}
9922 getMargins : function(side){
9925 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9926 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9927 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9928 right: parseInt(this.getStyle("margin-right"), 10) || 0
9931 return this.addStyles(side, El.margins);
9936 addStyles : function(sides, styles){
9938 for(var i = 0, len = sides.length; i < len; i++){
9939 v = this.getStyle(styles[sides.charAt(i)]);
9941 w = parseInt(v, 10);
9949 * Creates a proxy element of this element
9950 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9951 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9952 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9953 * @return {Roo.Element} The new proxy element
9955 createProxy : function(config, renderTo, matchBox){
9957 renderTo = Roo.getDom(renderTo);
9959 renderTo = document.body;
9961 config = typeof config == "object" ?
9962 config : {tag : "div", cls: config};
9963 var proxy = Roo.DomHelper.append(renderTo, config, true);
9965 proxy.setBox(this.getBox());
9971 * Puts a mask over this element to disable user interaction. Requires core.css.
9972 * This method can only be applied to elements which accept child nodes.
9973 * @param {String} msg (optional) A message to display in the mask
9974 * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
9975 * @return {Element} The mask element
9977 mask : function(msg, msgCls)
9979 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9980 this.setStyle("position", "relative");
9983 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9986 this.addClass("x-masked");
9987 this._mask.setDisplayed(true);
9992 while (dom && dom.style) {
9993 if (!isNaN(parseInt(dom.style.zIndex))) {
9994 z = Math.max(z, parseInt(dom.style.zIndex));
9996 dom = dom.parentNode;
9998 // if we are masking the body - then it hides everything..
9999 if (this.dom == document.body) {
10001 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10002 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10005 if(typeof msg == 'string'){
10006 if(!this._maskMsg){
10007 this._maskMsg = Roo.DomHelper.append(this.dom, {
10008 cls: "roo-el-mask-msg",
10012 cls: 'fa fa-spinner fa-spin'
10020 var mm = this._maskMsg;
10021 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10022 if (mm.dom.lastChild) { // weird IE issue?
10023 mm.dom.lastChild.innerHTML = msg;
10025 mm.setDisplayed(true);
10027 mm.setStyle('z-index', z + 102);
10029 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10030 this._mask.setHeight(this.getHeight());
10032 this._mask.setStyle('z-index', z + 100);
10038 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10039 * it is cached for reuse.
10041 unmask : function(removeEl){
10043 if(removeEl === true){
10044 this._mask.remove();
10047 this._maskMsg.remove();
10048 delete this._maskMsg;
10051 this._mask.setDisplayed(false);
10053 this._maskMsg.setDisplayed(false);
10057 this.removeClass("x-masked");
10061 * Returns true if this element is masked
10062 * @return {Boolean}
10064 isMasked : function(){
10065 return this._mask && this._mask.isVisible();
10069 * Creates an iframe shim for this element to keep selects and other windowed objects from
10071 * @return {Roo.Element} The new shim element
10073 createShim : function(){
10074 var el = document.createElement('iframe');
10075 el.frameBorder = 'no';
10076 el.className = 'roo-shim';
10077 if(Roo.isIE && Roo.isSecure){
10078 el.src = Roo.SSL_SECURE_URL;
10080 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10081 shim.autoBoxAdjust = false;
10086 * Removes this element from the DOM and deletes it from the cache
10088 remove : function(){
10089 if(this.dom.parentNode){
10090 this.dom.parentNode.removeChild(this.dom);
10092 delete El.cache[this.dom.id];
10096 * Sets up event handlers to add and remove a css class when the mouse is over this element
10097 * @param {String} className
10098 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10099 * mouseout events for children elements
10100 * @return {Roo.Element} this
10102 addClassOnOver : function(className, preventFlicker){
10103 this.on("mouseover", function(){
10104 Roo.fly(this, '_internal').addClass(className);
10106 var removeFn = function(e){
10107 if(preventFlicker !== true || !e.within(this, true)){
10108 Roo.fly(this, '_internal').removeClass(className);
10111 this.on("mouseout", removeFn, this.dom);
10116 * Sets up event handlers to add and remove a css class when this element has the focus
10117 * @param {String} className
10118 * @return {Roo.Element} this
10120 addClassOnFocus : function(className){
10121 this.on("focus", function(){
10122 Roo.fly(this, '_internal').addClass(className);
10124 this.on("blur", function(){
10125 Roo.fly(this, '_internal').removeClass(className);
10130 * 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)
10131 * @param {String} className
10132 * @return {Roo.Element} this
10134 addClassOnClick : function(className){
10135 var dom = this.dom;
10136 this.on("mousedown", function(){
10137 Roo.fly(dom, '_internal').addClass(className);
10138 var d = Roo.get(document);
10139 var fn = function(){
10140 Roo.fly(dom, '_internal').removeClass(className);
10141 d.removeListener("mouseup", fn);
10143 d.on("mouseup", fn);
10149 * Stops the specified event from bubbling and optionally prevents the default action
10150 * @param {String} eventName
10151 * @param {Boolean} preventDefault (optional) true to prevent the default action too
10152 * @return {Roo.Element} this
10154 swallowEvent : function(eventName, preventDefault){
10155 var fn = function(e){
10156 e.stopPropagation();
10157 if(preventDefault){
10158 e.preventDefault();
10161 if(eventName instanceof Array){
10162 for(var i = 0, len = eventName.length; i < len; i++){
10163 this.on(eventName[i], fn);
10167 this.on(eventName, fn);
10174 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10177 * Sizes this element to its parent element's dimensions performing
10178 * neccessary box adjustments.
10179 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10180 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10181 * @return {Roo.Element} this
10183 fitToParent : function(monitorResize, targetParent) {
10184 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10185 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10186 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10189 var p = Roo.get(targetParent || this.dom.parentNode);
10190 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10191 if (monitorResize === true) {
10192 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10193 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10199 * Gets the next sibling, skipping text nodes
10200 * @return {HTMLElement} The next sibling or null
10202 getNextSibling : function(){
10203 var n = this.dom.nextSibling;
10204 while(n && n.nodeType != 1){
10211 * Gets the previous sibling, skipping text nodes
10212 * @return {HTMLElement} The previous sibling or null
10214 getPrevSibling : function(){
10215 var n = this.dom.previousSibling;
10216 while(n && n.nodeType != 1){
10217 n = n.previousSibling;
10224 * Appends the passed element(s) to this element
10225 * @param {String/HTMLElement/Array/Element/CompositeElement} el
10226 * @return {Roo.Element} this
10228 appendChild: function(el){
10235 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10236 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
10237 * automatically generated with the specified attributes.
10238 * @param {HTMLElement} insertBefore (optional) a child element of this element
10239 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10240 * @return {Roo.Element} The new child element
10242 createChild: function(config, insertBefore, returnDom){
10243 config = config || {tag:'div'};
10245 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10247 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
10251 * Appends this element to the passed element
10252 * @param {String/HTMLElement/Element} el The new parent element
10253 * @return {Roo.Element} this
10255 appendTo: function(el){
10256 el = Roo.getDom(el);
10257 el.appendChild(this.dom);
10262 * Inserts this element before the passed element in the DOM
10263 * @param {String/HTMLElement/Element} el The element to insert before
10264 * @return {Roo.Element} this
10266 insertBefore: function(el){
10267 el = Roo.getDom(el);
10268 el.parentNode.insertBefore(this.dom, el);
10273 * Inserts this element after the passed element in the DOM
10274 * @param {String/HTMLElement/Element} el The element to insert after
10275 * @return {Roo.Element} this
10277 insertAfter: function(el){
10278 el = Roo.getDom(el);
10279 el.parentNode.insertBefore(this.dom, el.nextSibling);
10284 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10285 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10286 * @return {Roo.Element} The new child
10288 insertFirst: function(el, returnDom){
10290 if(typeof el == 'object' && !el.nodeType){ // dh config
10291 return this.createChild(el, this.dom.firstChild, returnDom);
10293 el = Roo.getDom(el);
10294 this.dom.insertBefore(el, this.dom.firstChild);
10295 return !returnDom ? Roo.get(el) : el;
10300 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10301 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10302 * @param {String} where (optional) 'before' or 'after' defaults to before
10303 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10304 * @return {Roo.Element} the inserted Element
10306 insertSibling: function(el, where, returnDom){
10307 where = where ? where.toLowerCase() : 'before';
10309 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10311 if(typeof el == 'object' && !el.nodeType){ // dh config
10312 if(where == 'after' && !this.dom.nextSibling){
10313 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10315 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10319 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10320 where == 'before' ? this.dom : this.dom.nextSibling);
10329 * Creates and wraps this element with another element
10330 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10331 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10332 * @return {HTMLElement/Element} The newly created wrapper element
10334 wrap: function(config, returnDom){
10336 config = {tag: "div"};
10338 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10339 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10344 * Replaces the passed element with this element
10345 * @param {String/HTMLElement/Element} el The element to replace
10346 * @return {Roo.Element} this
10348 replace: function(el){
10350 this.insertBefore(el);
10356 * Inserts an html fragment into this element
10357 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10358 * @param {String} html The HTML fragment
10359 * @param {Boolean} returnEl True to return an Roo.Element
10360 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10362 insertHtml : function(where, html, returnEl){
10363 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10364 return returnEl ? Roo.get(el) : el;
10368 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10369 * @param {Object} o The object with the attributes
10370 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10371 * @return {Roo.Element} this
10373 set : function(o, useSet){
10375 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10376 for(var attr in o){
10377 if(attr == "style" || typeof o[attr] == "function") { continue; }
10379 el.className = o["cls"];
10382 el.setAttribute(attr, o[attr]);
10384 el[attr] = o[attr];
10389 Roo.DomHelper.applyStyles(el, o.style);
10395 * Convenience method for constructing a KeyMap
10396 * @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:
10397 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10398 * @param {Function} fn The function to call
10399 * @param {Object} scope (optional) The scope of the function
10400 * @return {Roo.KeyMap} The KeyMap created
10402 addKeyListener : function(key, fn, scope){
10404 if(typeof key != "object" || key instanceof Array){
10420 return new Roo.KeyMap(this, config);
10424 * Creates a KeyMap for this element
10425 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10426 * @return {Roo.KeyMap} The KeyMap created
10428 addKeyMap : function(config){
10429 return new Roo.KeyMap(this, config);
10433 * Returns true if this element is scrollable.
10434 * @return {Boolean}
10436 isScrollable : function(){
10437 var dom = this.dom;
10438 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10442 * 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().
10443 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10444 * @param {Number} value The new scroll value
10445 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10446 * @return {Element} this
10449 scrollTo : function(side, value, animate){
10450 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10451 if(!animate || !A){
10452 this.dom[prop] = value;
10454 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10455 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10461 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10462 * within this element's scrollable range.
10463 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10464 * @param {Number} distance How far to scroll the element in pixels
10465 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10466 * @return {Boolean} Returns true if a scroll was triggered or false if the element
10467 * was scrolled as far as it could go.
10469 scroll : function(direction, distance, animate){
10470 if(!this.isScrollable()){
10474 var l = el.scrollLeft, t = el.scrollTop;
10475 var w = el.scrollWidth, h = el.scrollHeight;
10476 var cw = el.clientWidth, ch = el.clientHeight;
10477 direction = direction.toLowerCase();
10478 var scrolled = false;
10479 var a = this.preanim(arguments, 2);
10484 var v = Math.min(l + distance, w-cw);
10485 this.scrollTo("left", v, a);
10492 var v = Math.max(l - distance, 0);
10493 this.scrollTo("left", v, a);
10501 var v = Math.max(t - distance, 0);
10502 this.scrollTo("top", v, a);
10510 var v = Math.min(t + distance, h-ch);
10511 this.scrollTo("top", v, a);
10520 * Translates the passed page coordinates into left/top css values for this element
10521 * @param {Number/Array} x The page x or an array containing [x, y]
10522 * @param {Number} y The page y
10523 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10525 translatePoints : function(x, y){
10526 if(typeof x == 'object' || x instanceof Array){
10527 y = x[1]; x = x[0];
10529 var p = this.getStyle('position');
10530 var o = this.getXY();
10532 var l = parseInt(this.getStyle('left'), 10);
10533 var t = parseInt(this.getStyle('top'), 10);
10536 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10539 t = (p == "relative") ? 0 : this.dom.offsetTop;
10542 return {left: (x - o[0] + l), top: (y - o[1] + t)};
10546 * Returns the current scroll position of the element.
10547 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10549 getScroll : function(){
10550 var d = this.dom, doc = document;
10551 if(d == doc || d == doc.body){
10552 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10553 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10554 return {left: l, top: t};
10556 return {left: d.scrollLeft, top: d.scrollTop};
10561 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10562 * are convert to standard 6 digit hex color.
10563 * @param {String} attr The css attribute
10564 * @param {String} defaultValue The default value to use when a valid color isn't found
10565 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10568 getColor : function(attr, defaultValue, prefix){
10569 var v = this.getStyle(attr);
10570 if(!v || v == "transparent" || v == "inherit") {
10571 return defaultValue;
10573 var color = typeof prefix == "undefined" ? "#" : prefix;
10574 if(v.substr(0, 4) == "rgb("){
10575 var rvs = v.slice(4, v.length -1).split(",");
10576 for(var i = 0; i < 3; i++){
10577 var h = parseInt(rvs[i]).toString(16);
10584 if(v.substr(0, 1) == "#"){
10585 if(v.length == 4) {
10586 for(var i = 1; i < 4; i++){
10587 var c = v.charAt(i);
10590 }else if(v.length == 7){
10591 color += v.substr(1);
10595 return(color.length > 5 ? color.toLowerCase() : defaultValue);
10599 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10600 * gradient background, rounded corners and a 4-way shadow.
10601 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10602 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
10603 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
10604 * @return {Roo.Element} this
10606 boxWrap : function(cls){
10607 cls = cls || 'x-box';
10608 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
10609 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
10614 * Returns the value of a namespaced attribute from the element's underlying DOM node.
10615 * @param {String} namespace The namespace in which to look for the attribute
10616 * @param {String} name The attribute name
10617 * @return {String} The attribute value
10619 getAttributeNS : Roo.isIE ? function(ns, name){
10621 var type = typeof d[ns+":"+name];
10622 if(type != 'undefined' && type != 'unknown'){
10623 return d[ns+":"+name];
10626 } : function(ns, name){
10628 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
10633 * Sets or Returns the value the dom attribute value
10634 * @param {String|Object} name The attribute name (or object to set multiple attributes)
10635 * @param {String} value (optional) The value to set the attribute to
10636 * @return {String} The attribute value
10638 attr : function(name){
10639 if (arguments.length > 1) {
10640 this.dom.setAttribute(name, arguments[1]);
10641 return arguments[1];
10643 if (typeof(name) == 'object') {
10644 for(var i in name) {
10645 this.attr(i, name[i]);
10651 if (!this.dom.hasAttribute(name)) {
10654 return this.dom.getAttribute(name);
10661 var ep = El.prototype;
10664 * Appends an event handler (Shorthand for addListener)
10665 * @param {String} eventName The type of event to append
10666 * @param {Function} fn The method the event invokes
10667 * @param {Object} scope (optional) The scope (this object) of the fn
10668 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
10671 ep.on = ep.addListener;
10672 // backwards compat
10673 ep.mon = ep.addListener;
10676 * Removes an event handler from this element (shorthand for removeListener)
10677 * @param {String} eventName the type of event to remove
10678 * @param {Function} fn the method the event invokes
10679 * @return {Roo.Element} this
10682 ep.un = ep.removeListener;
10685 * true to automatically adjust width and height settings for box-model issues (default to true)
10687 ep.autoBoxAdjust = true;
10690 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
10693 El.addUnits = function(v, defaultUnit){
10694 if(v === "" || v == "auto"){
10697 if(v === undefined){
10700 if(typeof v == "number" || !El.unitPattern.test(v)){
10701 return v + (defaultUnit || 'px');
10706 // special markup used throughout Roo when box wrapping elements
10707 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>';
10709 * Visibility mode constant - Use visibility to hide element
10715 * Visibility mode constant - Use display to hide element
10721 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10722 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10723 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10735 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10736 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10737 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10738 * @return {Element} The Element object
10741 El.get = function(el){
10743 if(!el){ return null; }
10744 if(typeof el == "string"){ // element id
10745 if(!(elm = document.getElementById(el))){
10748 if(ex = El.cache[el]){
10751 ex = El.cache[el] = new El(elm);
10754 }else if(el.tagName){ // dom element
10758 if(ex = El.cache[id]){
10761 ex = El.cache[id] = new El(el);
10764 }else if(el instanceof El){
10766 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10767 // catch case where it hasn't been appended
10768 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10771 }else if(el.isComposite){
10773 }else if(el instanceof Array){
10774 return El.select(el);
10775 }else if(el == document){
10776 // create a bogus element object representing the document object
10778 var f = function(){};
10779 f.prototype = El.prototype;
10781 docEl.dom = document;
10789 El.uncache = function(el){
10790 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10792 delete El.cache[a[i].id || a[i]];
10798 // Garbage collection - uncache elements/purge listeners on orphaned elements
10799 // so we don't hold a reference and cause the browser to retain them
10800 El.garbageCollect = function(){
10801 if(!Roo.enableGarbageCollector){
10802 clearInterval(El.collectorThread);
10805 for(var eid in El.cache){
10806 var el = El.cache[eid], d = el.dom;
10807 // -------------------------------------------------------
10808 // Determining what is garbage:
10809 // -------------------------------------------------------
10811 // dom node is null, definitely garbage
10812 // -------------------------------------------------------
10814 // no parentNode == direct orphan, definitely garbage
10815 // -------------------------------------------------------
10816 // !d.offsetParent && !document.getElementById(eid)
10817 // display none elements have no offsetParent so we will
10818 // also try to look it up by it's id. However, check
10819 // offsetParent first so we don't do unneeded lookups.
10820 // This enables collection of elements that are not orphans
10821 // directly, but somewhere up the line they have an orphan
10823 // -------------------------------------------------------
10824 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10825 delete El.cache[eid];
10826 if(d && Roo.enableListenerCollection){
10832 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10836 El.Flyweight = function(dom){
10839 El.Flyweight.prototype = El.prototype;
10841 El._flyweights = {};
10843 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10844 * the dom node can be overwritten by other code.
10845 * @param {String/HTMLElement} el The dom node or id
10846 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10847 * prevent conflicts (e.g. internally Roo uses "_internal")
10849 * @return {Element} The shared Element object
10851 El.fly = function(el, named){
10852 named = named || '_global';
10853 el = Roo.getDom(el);
10857 if(!El._flyweights[named]){
10858 El._flyweights[named] = new El.Flyweight();
10860 El._flyweights[named].dom = el;
10861 return El._flyweights[named];
10865 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10866 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10867 * Shorthand of {@link Roo.Element#get}
10868 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10869 * @return {Element} The Element object
10875 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10876 * the dom node can be overwritten by other code.
10877 * Shorthand of {@link Roo.Element#fly}
10878 * @param {String/HTMLElement} el The dom node or id
10879 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10880 * prevent conflicts (e.g. internally Roo uses "_internal")
10882 * @return {Element} The shared Element object
10888 // speedy lookup for elements never to box adjust
10889 var noBoxAdjust = Roo.isStrict ? {
10892 input:1, select:1, textarea:1
10894 if(Roo.isIE || Roo.isGecko){
10895 noBoxAdjust['button'] = 1;
10899 Roo.EventManager.on(window, 'unload', function(){
10901 delete El._flyweights;
10909 Roo.Element.selectorFunction = Roo.DomQuery.select;
10912 Roo.Element.select = function(selector, unique, root){
10914 if(typeof selector == "string"){
10915 els = Roo.Element.selectorFunction(selector, root);
10916 }else if(selector.length !== undefined){
10919 throw "Invalid selector";
10921 if(unique === true){
10922 return new Roo.CompositeElement(els);
10924 return new Roo.CompositeElementLite(els);
10928 * Selects elements based on the passed CSS selector to enable working on them as 1.
10929 * @param {String/Array} selector The CSS selector or an array of elements
10930 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10931 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10932 * @return {CompositeElementLite/CompositeElement}
10936 Roo.select = Roo.Element.select;
10953 * Ext JS Library 1.1.1
10954 * Copyright(c) 2006-2007, Ext JS, LLC.
10956 * Originally Released Under LGPL - original licence link has changed is not relivant.
10959 * <script type="text/javascript">
10964 //Notifies Element that fx methods are available
10965 Roo.enableFx = true;
10969 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10970 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10971 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10972 * Element effects to work.</p><br/>
10974 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10975 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10976 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10977 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10978 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10979 * expected results and should be done with care.</p><br/>
10981 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10982 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10985 ----- -----------------------------
10986 tl The top left corner
10987 t The center of the top edge
10988 tr The top right corner
10989 l The center of the left edge
10990 r The center of the right edge
10991 bl The bottom left corner
10992 b The center of the bottom edge
10993 br The bottom right corner
10995 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10996 * below are common options that can be passed to any Fx method.</b>
10997 * @cfg {Function} callback A function called when the effect is finished
10998 * @cfg {Object} scope The scope of the effect function
10999 * @cfg {String} easing A valid Easing value for the effect
11000 * @cfg {String} afterCls A css class to apply after the effect
11001 * @cfg {Number} duration The length of time (in seconds) that the effect should last
11002 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11003 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
11004 * effects that end with the element being visually hidden, ignored otherwise)
11005 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11006 * a function which returns such a specification that will be applied to the Element after the effect finishes
11007 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11008 * @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
11009 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11013 * Slides the element into view. An anchor point can be optionally passed to set the point of
11014 * origin for the slide effect. This function automatically handles wrapping the element with
11015 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11018 // default: slide the element in from the top
11021 // custom: slide the element in from the right with a 2-second duration
11022 el.slideIn('r', { duration: 2 });
11024 // common config options shown with default values
11030 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11031 * @param {Object} options (optional) Object literal with any of the Fx config options
11032 * @return {Roo.Element} The Element
11034 slideIn : function(anchor, o){
11035 var el = this.getFxEl();
11038 el.queueFx(o, function(){
11040 anchor = anchor || "t";
11042 // fix display to visibility
11045 // restore values after effect
11046 var r = this.getFxRestore();
11047 var b = this.getBox();
11048 // fixed size for slide
11052 var wrap = this.fxWrap(r.pos, o, "hidden");
11054 var st = this.dom.style;
11055 st.visibility = "visible";
11056 st.position = "absolute";
11058 // clear out temp styles after slide and unwrap
11059 var after = function(){
11060 el.fxUnwrap(wrap, r.pos, o);
11061 st.width = r.width;
11062 st.height = r.height;
11065 // time to calc the positions
11066 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11068 switch(anchor.toLowerCase()){
11070 wrap.setSize(b.width, 0);
11071 st.left = st.bottom = "0";
11075 wrap.setSize(0, b.height);
11076 st.right = st.top = "0";
11080 wrap.setSize(0, b.height);
11081 wrap.setX(b.right);
11082 st.left = st.top = "0";
11083 a = {width: bw, points: pt};
11086 wrap.setSize(b.width, 0);
11087 wrap.setY(b.bottom);
11088 st.left = st.top = "0";
11089 a = {height: bh, points: pt};
11092 wrap.setSize(0, 0);
11093 st.right = st.bottom = "0";
11094 a = {width: bw, height: bh};
11097 wrap.setSize(0, 0);
11098 wrap.setY(b.y+b.height);
11099 st.right = st.top = "0";
11100 a = {width: bw, height: bh, points: pt};
11103 wrap.setSize(0, 0);
11104 wrap.setXY([b.right, b.bottom]);
11105 st.left = st.top = "0";
11106 a = {width: bw, height: bh, points: pt};
11109 wrap.setSize(0, 0);
11110 wrap.setX(b.x+b.width);
11111 st.left = st.bottom = "0";
11112 a = {width: bw, height: bh, points: pt};
11115 this.dom.style.visibility = "visible";
11118 arguments.callee.anim = wrap.fxanim(a,
11128 * Slides the element out of view. An anchor point can be optionally passed to set the end point
11129 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
11130 * 'hidden') but block elements will still take up space in the document. The element must be removed
11131 * from the DOM using the 'remove' config option if desired. This function automatically handles
11132 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11135 // default: slide the element out to the top
11138 // custom: slide the element out to the right with a 2-second duration
11139 el.slideOut('r', { duration: 2 });
11141 // common config options shown with default values
11149 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11150 * @param {Object} options (optional) Object literal with any of the Fx config options
11151 * @return {Roo.Element} The Element
11153 slideOut : function(anchor, o){
11154 var el = this.getFxEl();
11157 el.queueFx(o, function(){
11159 anchor = anchor || "t";
11161 // restore values after effect
11162 var r = this.getFxRestore();
11164 var b = this.getBox();
11165 // fixed size for slide
11169 var wrap = this.fxWrap(r.pos, o, "visible");
11171 var st = this.dom.style;
11172 st.visibility = "visible";
11173 st.position = "absolute";
11177 var after = function(){
11179 el.setDisplayed(false);
11184 el.fxUnwrap(wrap, r.pos, o);
11186 st.width = r.width;
11187 st.height = r.height;
11192 var a, zero = {to: 0};
11193 switch(anchor.toLowerCase()){
11195 st.left = st.bottom = "0";
11196 a = {height: zero};
11199 st.right = st.top = "0";
11203 st.left = st.top = "0";
11204 a = {width: zero, points: {to:[b.right, b.y]}};
11207 st.left = st.top = "0";
11208 a = {height: zero, points: {to:[b.x, b.bottom]}};
11211 st.right = st.bottom = "0";
11212 a = {width: zero, height: zero};
11215 st.right = st.top = "0";
11216 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11219 st.left = st.top = "0";
11220 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11223 st.left = st.bottom = "0";
11224 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11228 arguments.callee.anim = wrap.fxanim(a,
11238 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
11239 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
11240 * The element must be removed from the DOM using the 'remove' config option if desired.
11246 // common config options shown with default values
11254 * @param {Object} options (optional) Object literal with any of the Fx config options
11255 * @return {Roo.Element} The Element
11257 puff : function(o){
11258 var el = this.getFxEl();
11261 el.queueFx(o, function(){
11262 this.clearOpacity();
11265 // restore values after effect
11266 var r = this.getFxRestore();
11267 var st = this.dom.style;
11269 var after = function(){
11271 el.setDisplayed(false);
11278 el.setPositioning(r.pos);
11279 st.width = r.width;
11280 st.height = r.height;
11285 var width = this.getWidth();
11286 var height = this.getHeight();
11288 arguments.callee.anim = this.fxanim({
11289 width : {to: this.adjustWidth(width * 2)},
11290 height : {to: this.adjustHeight(height * 2)},
11291 points : {by: [-(width * .5), -(height * .5)]},
11293 fontSize: {to:200, unit: "%"}
11304 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11305 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
11306 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11312 // all config options shown with default values
11320 * @param {Object} options (optional) Object literal with any of the Fx config options
11321 * @return {Roo.Element} The Element
11323 switchOff : function(o){
11324 var el = this.getFxEl();
11327 el.queueFx(o, function(){
11328 this.clearOpacity();
11331 // restore values after effect
11332 var r = this.getFxRestore();
11333 var st = this.dom.style;
11335 var after = function(){
11337 el.setDisplayed(false);
11343 el.setPositioning(r.pos);
11344 st.width = r.width;
11345 st.height = r.height;
11350 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11351 this.clearOpacity();
11355 points:{by:[0, this.getHeight() * .5]}
11356 }, o, 'motion', 0.3, 'easeIn', after);
11357 }).defer(100, this);
11364 * Highlights the Element by setting a color (applies to the background-color by default, but can be
11365 * changed using the "attr" config option) and then fading back to the original color. If no original
11366 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11369 // default: highlight background to yellow
11372 // custom: highlight foreground text to blue for 2 seconds
11373 el.highlight("0000ff", { attr: 'color', duration: 2 });
11375 // common config options shown with default values
11376 el.highlight("ffff9c", {
11377 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11378 endColor: (current color) or "ffffff",
11383 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11384 * @param {Object} options (optional) Object literal with any of the Fx config options
11385 * @return {Roo.Element} The Element
11387 highlight : function(color, o){
11388 var el = this.getFxEl();
11391 el.queueFx(o, function(){
11392 color = color || "ffff9c";
11393 attr = o.attr || "backgroundColor";
11395 this.clearOpacity();
11398 var origColor = this.getColor(attr);
11399 var restoreColor = this.dom.style[attr];
11400 endColor = (o.endColor || origColor) || "ffffff";
11402 var after = function(){
11403 el.dom.style[attr] = restoreColor;
11408 a[attr] = {from: color, to: endColor};
11409 arguments.callee.anim = this.fxanim(a,
11419 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11422 // default: a single light blue ripple
11425 // custom: 3 red ripples lasting 3 seconds total
11426 el.frame("ff0000", 3, { duration: 3 });
11428 // common config options shown with default values
11429 el.frame("C3DAF9", 1, {
11430 duration: 1 //duration of entire animation (not each individual ripple)
11431 // Note: Easing is not configurable and will be ignored if included
11434 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11435 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11436 * @param {Object} options (optional) Object literal with any of the Fx config options
11437 * @return {Roo.Element} The Element
11439 frame : function(color, count, o){
11440 var el = this.getFxEl();
11443 el.queueFx(o, function(){
11444 color = color || "#C3DAF9";
11445 if(color.length == 6){
11446 color = "#" + color;
11448 count = count || 1;
11449 duration = o.duration || 1;
11452 var b = this.getBox();
11453 var animFn = function(){
11454 var proxy = this.createProxy({
11457 visbility:"hidden",
11458 position:"absolute",
11459 "z-index":"35000", // yee haw
11460 border:"0px solid " + color
11463 var scale = Roo.isBorderBox ? 2 : 1;
11465 top:{from:b.y, to:b.y - 20},
11466 left:{from:b.x, to:b.x - 20},
11467 borderWidth:{from:0, to:10},
11468 opacity:{from:1, to:0},
11469 height:{from:b.height, to:(b.height + (20*scale))},
11470 width:{from:b.width, to:(b.width + (20*scale))}
11471 }, duration, function(){
11475 animFn.defer((duration/2)*1000, this);
11486 * Creates a pause before any subsequent queued effects begin. If there are
11487 * no effects queued after the pause it will have no effect.
11492 * @param {Number} seconds The length of time to pause (in seconds)
11493 * @return {Roo.Element} The Element
11495 pause : function(seconds){
11496 var el = this.getFxEl();
11499 el.queueFx(o, function(){
11500 setTimeout(function(){
11502 }, seconds * 1000);
11508 * Fade an element in (from transparent to opaque). The ending opacity can be specified
11509 * using the "endOpacity" config option.
11512 // default: fade in from opacity 0 to 100%
11515 // custom: fade in from opacity 0 to 75% over 2 seconds
11516 el.fadeIn({ endOpacity: .75, duration: 2});
11518 // common config options shown with default values
11520 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11525 * @param {Object} options (optional) Object literal with any of the Fx config options
11526 * @return {Roo.Element} The Element
11528 fadeIn : function(o){
11529 var el = this.getFxEl();
11531 el.queueFx(o, function(){
11532 this.setOpacity(0);
11534 this.dom.style.visibility = 'visible';
11535 var to = o.endOpacity || 1;
11536 arguments.callee.anim = this.fxanim({opacity:{to:to}},
11537 o, null, .5, "easeOut", function(){
11539 this.clearOpacity();
11548 * Fade an element out (from opaque to transparent). The ending opacity can be specified
11549 * using the "endOpacity" config option.
11552 // default: fade out from the element's current opacity to 0
11555 // custom: fade out from the element's current opacity to 25% over 2 seconds
11556 el.fadeOut({ endOpacity: .25, duration: 2});
11558 // common config options shown with default values
11560 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11567 * @param {Object} options (optional) Object literal with any of the Fx config options
11568 * @return {Roo.Element} The Element
11570 fadeOut : function(o){
11571 var el = this.getFxEl();
11573 el.queueFx(o, function(){
11574 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11575 o, null, .5, "easeOut", function(){
11576 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11577 this.dom.style.display = "none";
11579 this.dom.style.visibility = "hidden";
11581 this.clearOpacity();
11589 * Animates the transition of an element's dimensions from a starting height/width
11590 * to an ending height/width.
11593 // change height and width to 100x100 pixels
11594 el.scale(100, 100);
11596 // common config options shown with default values. The height and width will default to
11597 // the element's existing values if passed as null.
11600 [element's height], {
11605 * @param {Number} width The new width (pass undefined to keep the original width)
11606 * @param {Number} height The new height (pass undefined to keep the original height)
11607 * @param {Object} options (optional) Object literal with any of the Fx config options
11608 * @return {Roo.Element} The Element
11610 scale : function(w, h, o){
11611 this.shift(Roo.apply({}, o, {
11619 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
11620 * Any of these properties not specified in the config object will not be changed. This effect
11621 * requires that at least one new dimension, position or opacity setting must be passed in on
11622 * the config object in order for the function to have any effect.
11625 // slide the element horizontally to x position 200 while changing the height and opacity
11626 el.shift({ x: 200, height: 50, opacity: .8 });
11628 // common config options shown with default values.
11630 width: [element's width],
11631 height: [element's height],
11632 x: [element's x position],
11633 y: [element's y position],
11634 opacity: [element's opacity],
11639 * @param {Object} options Object literal with any of the Fx config options
11640 * @return {Roo.Element} The Element
11642 shift : function(o){
11643 var el = this.getFxEl();
11645 el.queueFx(o, function(){
11646 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
11647 if(w !== undefined){
11648 a.width = {to: this.adjustWidth(w)};
11650 if(h !== undefined){
11651 a.height = {to: this.adjustHeight(h)};
11653 if(x !== undefined || y !== undefined){
11655 x !== undefined ? x : this.getX(),
11656 y !== undefined ? y : this.getY()
11659 if(op !== undefined){
11660 a.opacity = {to: op};
11662 if(o.xy !== undefined){
11663 a.points = {to: o.xy};
11665 arguments.callee.anim = this.fxanim(a,
11666 o, 'motion', .35, "easeOut", function(){
11674 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
11675 * ending point of the effect.
11678 // default: slide the element downward while fading out
11681 // custom: slide the element out to the right with a 2-second duration
11682 el.ghost('r', { duration: 2 });
11684 // common config options shown with default values
11692 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
11693 * @param {Object} options (optional) Object literal with any of the Fx config options
11694 * @return {Roo.Element} The Element
11696 ghost : function(anchor, o){
11697 var el = this.getFxEl();
11700 el.queueFx(o, function(){
11701 anchor = anchor || "b";
11703 // restore values after effect
11704 var r = this.getFxRestore();
11705 var w = this.getWidth(),
11706 h = this.getHeight();
11708 var st = this.dom.style;
11710 var after = function(){
11712 el.setDisplayed(false);
11718 el.setPositioning(r.pos);
11719 st.width = r.width;
11720 st.height = r.height;
11725 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11726 switch(anchor.toLowerCase()){
11753 arguments.callee.anim = this.fxanim(a,
11763 * Ensures that all effects queued after syncFx is called on the element are
11764 * run concurrently. This is the opposite of {@link #sequenceFx}.
11765 * @return {Roo.Element} The Element
11767 syncFx : function(){
11768 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11777 * Ensures that all effects queued after sequenceFx is called on the element are
11778 * run in sequence. This is the opposite of {@link #syncFx}.
11779 * @return {Roo.Element} The Element
11781 sequenceFx : function(){
11782 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11784 concurrent : false,
11791 nextFx : function(){
11792 var ef = this.fxQueue[0];
11799 * Returns true if the element has any effects actively running or queued, else returns false.
11800 * @return {Boolean} True if element has active effects, else false
11802 hasActiveFx : function(){
11803 return this.fxQueue && this.fxQueue[0];
11807 * Stops any running effects and clears the element's internal effects queue if it contains
11808 * any additional effects that haven't started yet.
11809 * @return {Roo.Element} The Element
11811 stopFx : function(){
11812 if(this.hasActiveFx()){
11813 var cur = this.fxQueue[0];
11814 if(cur && cur.anim && cur.anim.isAnimated()){
11815 this.fxQueue = [cur]; // clear out others
11816 cur.anim.stop(true);
11823 beforeFx : function(o){
11824 if(this.hasActiveFx() && !o.concurrent){
11835 * Returns true if the element is currently blocking so that no other effect can be queued
11836 * until this effect is finished, else returns false if blocking is not set. This is commonly
11837 * used to ensure that an effect initiated by a user action runs to completion prior to the
11838 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11839 * @return {Boolean} True if blocking, else false
11841 hasFxBlock : function(){
11842 var q = this.fxQueue;
11843 return q && q[0] && q[0].block;
11847 queueFx : function(o, fn){
11851 if(!this.hasFxBlock()){
11852 Roo.applyIf(o, this.fxDefaults);
11854 var run = this.beforeFx(o);
11855 fn.block = o.block;
11856 this.fxQueue.push(fn);
11868 fxWrap : function(pos, o, vis){
11870 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11873 wrapXY = this.getXY();
11875 var div = document.createElement("div");
11876 div.style.visibility = vis;
11877 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11878 wrap.setPositioning(pos);
11879 if(wrap.getStyle("position") == "static"){
11880 wrap.position("relative");
11882 this.clearPositioning('auto');
11884 wrap.dom.appendChild(this.dom);
11886 wrap.setXY(wrapXY);
11893 fxUnwrap : function(wrap, pos, o){
11894 this.clearPositioning();
11895 this.setPositioning(pos);
11897 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11903 getFxRestore : function(){
11904 var st = this.dom.style;
11905 return {pos: this.getPositioning(), width: st.width, height : st.height};
11909 afterFx : function(o){
11911 this.applyStyles(o.afterStyle);
11914 this.addClass(o.afterCls);
11916 if(o.remove === true){
11919 Roo.callback(o.callback, o.scope, [this]);
11921 this.fxQueue.shift();
11927 getFxEl : function(){ // support for composite element fx
11928 return Roo.get(this.dom);
11932 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11933 animType = animType || 'run';
11935 var anim = Roo.lib.Anim[animType](
11937 (opt.duration || defaultDur) || .35,
11938 (opt.easing || defaultEase) || 'easeOut',
11940 Roo.callback(cb, this);
11949 // backwords compat
11950 Roo.Fx.resize = Roo.Fx.scale;
11952 //When included, Roo.Fx is automatically applied to Element so that all basic
11953 //effects are available directly via the Element API
11954 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11956 * Ext JS Library 1.1.1
11957 * Copyright(c) 2006-2007, Ext JS, LLC.
11959 * Originally Released Under LGPL - original licence link has changed is not relivant.
11962 * <script type="text/javascript">
11967 * @class Roo.CompositeElement
11968 * Standard composite class. Creates a Roo.Element for every element in the collection.
11970 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11971 * actions will be performed on all the elements in this collection.</b>
11973 * All methods return <i>this</i> and can be chained.
11975 var els = Roo.select("#some-el div.some-class", true);
11976 // or select directly from an existing element
11977 var el = Roo.get('some-el');
11978 el.select('div.some-class', true);
11980 els.setWidth(100); // all elements become 100 width
11981 els.hide(true); // all elements fade out and hide
11983 els.setWidth(100).hide(true);
11986 Roo.CompositeElement = function(els){
11987 this.elements = [];
11988 this.addElements(els);
11990 Roo.CompositeElement.prototype = {
11992 addElements : function(els){
11996 if(typeof els == "string"){
11997 els = Roo.Element.selectorFunction(els);
11999 var yels = this.elements;
12000 var index = yels.length-1;
12001 for(var i = 0, len = els.length; i < len; i++) {
12002 yels[++index] = Roo.get(els[i]);
12008 * Clears this composite and adds the elements returned by the passed selector.
12009 * @param {String/Array} els A string CSS selector, an array of elements or an element
12010 * @return {CompositeElement} this
12012 fill : function(els){
12013 this.elements = [];
12019 * Filters this composite to only elements that match the passed selector.
12020 * @param {String} selector A string CSS selector
12021 * @param {Boolean} inverse return inverse filter (not matches)
12022 * @return {CompositeElement} this
12024 filter : function(selector, inverse){
12026 inverse = inverse || false;
12027 this.each(function(el){
12028 var match = inverse ? !el.is(selector) : el.is(selector);
12030 els[els.length] = el.dom;
12037 invoke : function(fn, args){
12038 var els = this.elements;
12039 for(var i = 0, len = els.length; i < len; i++) {
12040 Roo.Element.prototype[fn].apply(els[i], args);
12045 * Adds elements to this composite.
12046 * @param {String/Array} els A string CSS selector, an array of elements or an element
12047 * @return {CompositeElement} this
12049 add : function(els){
12050 if(typeof els == "string"){
12051 this.addElements(Roo.Element.selectorFunction(els));
12052 }else if(els.length !== undefined){
12053 this.addElements(els);
12055 this.addElements([els]);
12060 * Calls the passed function passing (el, this, index) for each element in this composite.
12061 * @param {Function} fn The function to call
12062 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12063 * @return {CompositeElement} this
12065 each : function(fn, scope){
12066 var els = this.elements;
12067 for(var i = 0, len = els.length; i < len; i++){
12068 if(fn.call(scope || els[i], els[i], this, i) === false) {
12076 * Returns the Element object at the specified index
12077 * @param {Number} index
12078 * @return {Roo.Element}
12080 item : function(index){
12081 return this.elements[index] || null;
12085 * Returns the first Element
12086 * @return {Roo.Element}
12088 first : function(){
12089 return this.item(0);
12093 * Returns the last Element
12094 * @return {Roo.Element}
12097 return this.item(this.elements.length-1);
12101 * Returns the number of elements in this composite
12104 getCount : function(){
12105 return this.elements.length;
12109 * Returns true if this composite contains the passed element
12112 contains : function(el){
12113 return this.indexOf(el) !== -1;
12117 * Returns true if this composite contains the passed element
12120 indexOf : function(el){
12121 return this.elements.indexOf(Roo.get(el));
12126 * Removes the specified element(s).
12127 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12128 * or an array of any of those.
12129 * @param {Boolean} removeDom (optional) True to also remove the element from the document
12130 * @return {CompositeElement} this
12132 removeElement : function(el, removeDom){
12133 if(el instanceof Array){
12134 for(var i = 0, len = el.length; i < len; i++){
12135 this.removeElement(el[i]);
12139 var index = typeof el == 'number' ? el : this.indexOf(el);
12142 var d = this.elements[index];
12146 d.parentNode.removeChild(d);
12149 this.elements.splice(index, 1);
12155 * Replaces the specified element with the passed element.
12156 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12158 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12159 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12160 * @return {CompositeElement} this
12162 replaceElement : function(el, replacement, domReplace){
12163 var index = typeof el == 'number' ? el : this.indexOf(el);
12166 this.elements[index].replaceWith(replacement);
12168 this.elements.splice(index, 1, Roo.get(replacement))
12175 * Removes all elements.
12177 clear : function(){
12178 this.elements = [];
12182 Roo.CompositeElement.createCall = function(proto, fnName){
12183 if(!proto[fnName]){
12184 proto[fnName] = function(){
12185 return this.invoke(fnName, arguments);
12189 for(var fnName in Roo.Element.prototype){
12190 if(typeof Roo.Element.prototype[fnName] == "function"){
12191 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12197 * Ext JS Library 1.1.1
12198 * Copyright(c) 2006-2007, Ext JS, LLC.
12200 * Originally Released Under LGPL - original licence link has changed is not relivant.
12203 * <script type="text/javascript">
12207 * @class Roo.CompositeElementLite
12208 * @extends Roo.CompositeElement
12209 * Flyweight composite class. Reuses the same Roo.Element for element operations.
12211 var els = Roo.select("#some-el div.some-class");
12212 // or select directly from an existing element
12213 var el = Roo.get('some-el');
12214 el.select('div.some-class');
12216 els.setWidth(100); // all elements become 100 width
12217 els.hide(true); // all elements fade out and hide
12219 els.setWidth(100).hide(true);
12220 </code></pre><br><br>
12221 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12222 * actions will be performed on all the elements in this collection.</b>
12224 Roo.CompositeElementLite = function(els){
12225 Roo.CompositeElementLite.superclass.constructor.call(this, els);
12226 this.el = new Roo.Element.Flyweight();
12228 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12229 addElements : function(els){
12231 if(els instanceof Array){
12232 this.elements = this.elements.concat(els);
12234 var yels = this.elements;
12235 var index = yels.length-1;
12236 for(var i = 0, len = els.length; i < len; i++) {
12237 yels[++index] = els[i];
12243 invoke : function(fn, args){
12244 var els = this.elements;
12246 for(var i = 0, len = els.length; i < len; i++) {
12248 Roo.Element.prototype[fn].apply(el, args);
12253 * Returns a flyweight Element of the dom element object at the specified index
12254 * @param {Number} index
12255 * @return {Roo.Element}
12257 item : function(index){
12258 if(!this.elements[index]){
12261 this.el.dom = this.elements[index];
12265 // fixes scope with flyweight
12266 addListener : function(eventName, handler, scope, opt){
12267 var els = this.elements;
12268 for(var i = 0, len = els.length; i < len; i++) {
12269 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12275 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12276 * passed is the flyweight (shared) Roo.Element instance, so if you require a
12277 * a reference to the dom node, use el.dom.</b>
12278 * @param {Function} fn The function to call
12279 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12280 * @return {CompositeElement} this
12282 each : function(fn, scope){
12283 var els = this.elements;
12285 for(var i = 0, len = els.length; i < len; i++){
12287 if(fn.call(scope || el, el, this, i) === false){
12294 indexOf : function(el){
12295 return this.elements.indexOf(Roo.getDom(el));
12298 replaceElement : function(el, replacement, domReplace){
12299 var index = typeof el == 'number' ? el : this.indexOf(el);
12301 replacement = Roo.getDom(replacement);
12303 var d = this.elements[index];
12304 d.parentNode.insertBefore(replacement, d);
12305 d.parentNode.removeChild(d);
12307 this.elements.splice(index, 1, replacement);
12312 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12316 * Ext JS Library 1.1.1
12317 * Copyright(c) 2006-2007, Ext JS, LLC.
12319 * Originally Released Under LGPL - original licence link has changed is not relivant.
12322 * <script type="text/javascript">
12328 * @class Roo.data.Connection
12329 * @extends Roo.util.Observable
12330 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12331 * either to a configured URL, or to a URL specified at request time.
12333 * Requests made by this class are asynchronous, and will return immediately. No data from
12334 * the server will be available to the statement immediately following the {@link #request} call.
12335 * To process returned data, use a callback in the request options object, or an event listener.
12337 * Note: If you are doing a file upload, you will not get a normal response object sent back to
12338 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12339 * The response object is created using the innerHTML of the IFRAME's document as the responseText
12340 * property and, if present, the IFRAME's XML document as the responseXML property.
12342 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12343 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
12344 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12345 * standard DOM methods.
12347 * @param {Object} config a configuration object.
12349 Roo.data.Connection = function(config){
12350 Roo.apply(this, config);
12353 * @event beforerequest
12354 * Fires before a network request is made to retrieve a data object.
12355 * @param {Connection} conn This Connection object.
12356 * @param {Object} options The options config object passed to the {@link #request} method.
12358 "beforerequest" : true,
12360 * @event requestcomplete
12361 * Fires if the request was successfully completed.
12362 * @param {Connection} conn This Connection object.
12363 * @param {Object} response The XHR object containing the response data.
12364 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12365 * @param {Object} options The options config object passed to the {@link #request} method.
12367 "requestcomplete" : true,
12369 * @event requestexception
12370 * Fires if an error HTTP status was returned from the server.
12371 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12372 * @param {Connection} conn This Connection object.
12373 * @param {Object} response The XHR object containing the response data.
12374 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12375 * @param {Object} options The options config object passed to the {@link #request} method.
12377 "requestexception" : true
12379 Roo.data.Connection.superclass.constructor.call(this);
12382 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12384 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12387 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12388 * extra parameters to each request made by this object. (defaults to undefined)
12391 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12392 * to each request made by this object. (defaults to undefined)
12395 * @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)
12398 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12402 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12408 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12411 disableCaching: true,
12414 * Sends an HTTP request to a remote server.
12415 * @param {Object} options An object which may contain the following properties:<ul>
12416 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12417 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12418 * request, a url encoded string or a function to call to get either.</li>
12419 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12420 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12421 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12422 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12423 * <li>options {Object} The parameter to the request call.</li>
12424 * <li>success {Boolean} True if the request succeeded.</li>
12425 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12427 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12428 * The callback is passed the following parameters:<ul>
12429 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12430 * <li>options {Object} The parameter to the request call.</li>
12432 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12433 * The callback is passed the following parameters:<ul>
12434 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12435 * <li>options {Object} The parameter to the request call.</li>
12437 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12438 * for the callback function. Defaults to the browser window.</li>
12439 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12440 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12441 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12442 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12443 * params for the post data. Any params will be appended to the URL.</li>
12444 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12446 * @return {Number} transactionId
12448 request : function(o){
12449 if(this.fireEvent("beforerequest", this, o) !== false){
12452 if(typeof p == "function"){
12453 p = p.call(o.scope||window, o);
12455 if(typeof p == "object"){
12456 p = Roo.urlEncode(o.params);
12458 if(this.extraParams){
12459 var extras = Roo.urlEncode(this.extraParams);
12460 p = p ? (p + '&' + extras) : extras;
12463 var url = o.url || this.url;
12464 if(typeof url == 'function'){
12465 url = url.call(o.scope||window, o);
12469 var form = Roo.getDom(o.form);
12470 url = url || form.action;
12472 var enctype = form.getAttribute("enctype");
12475 return this.doFormDataUpload(o, url);
12478 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12479 return this.doFormUpload(o, p, url);
12481 var f = Roo.lib.Ajax.serializeForm(form);
12482 p = p ? (p + '&' + f) : f;
12485 if (!o.form && o.formData) {
12486 o.formData = o.formData === true ? new FormData() : o.formData;
12487 for (var k in o.params) {
12488 o.formData.append(k,o.params[k]);
12491 return this.doFormDataUpload(o, url);
12495 var hs = o.headers;
12496 if(this.defaultHeaders){
12497 hs = Roo.apply(hs || {}, this.defaultHeaders);
12504 success: this.handleResponse,
12505 failure: this.handleFailure,
12507 argument: {options: o},
12508 timeout : o.timeout || this.timeout
12511 var method = o.method||this.method||(p ? "POST" : "GET");
12513 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12514 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12517 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12521 }else if(this.autoAbort !== false){
12525 if((method == 'GET' && p) || o.xmlData){
12526 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12529 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12530 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12531 Roo.lib.Ajax.useDefaultHeader == true;
12532 return this.transId;
12534 Roo.callback(o.callback, o.scope, [o, null, null]);
12540 * Determine whether this object has a request outstanding.
12541 * @param {Number} transactionId (Optional) defaults to the last transaction
12542 * @return {Boolean} True if there is an outstanding request.
12544 isLoading : function(transId){
12546 return Roo.lib.Ajax.isCallInProgress(transId);
12548 return this.transId ? true : false;
12553 * Aborts any outstanding request.
12554 * @param {Number} transactionId (Optional) defaults to the last transaction
12556 abort : function(transId){
12557 if(transId || this.isLoading()){
12558 Roo.lib.Ajax.abort(transId || this.transId);
12563 handleResponse : function(response){
12564 this.transId = false;
12565 var options = response.argument.options;
12566 response.argument = options ? options.argument : null;
12567 this.fireEvent("requestcomplete", this, response, options);
12568 Roo.callback(options.success, options.scope, [response, options]);
12569 Roo.callback(options.callback, options.scope, [options, true, response]);
12573 handleFailure : function(response, e){
12574 this.transId = false;
12575 var options = response.argument.options;
12576 response.argument = options ? options.argument : null;
12577 this.fireEvent("requestexception", this, response, options, e);
12578 Roo.callback(options.failure, options.scope, [response, options]);
12579 Roo.callback(options.callback, options.scope, [options, false, response]);
12583 doFormUpload : function(o, ps, url){
12585 var frame = document.createElement('iframe');
12588 frame.className = 'x-hidden';
12590 frame.src = Roo.SSL_SECURE_URL;
12592 document.body.appendChild(frame);
12595 document.frames[id].name = id;
12598 var form = Roo.getDom(o.form);
12600 form.method = 'POST';
12601 form.enctype = form.encoding = 'multipart/form-data';
12607 if(ps){ // add dynamic params
12609 ps = Roo.urlDecode(ps, false);
12611 if(ps.hasOwnProperty(k)){
12612 hd = document.createElement('input');
12613 hd.type = 'hidden';
12616 form.appendChild(hd);
12623 var r = { // bogus response object
12628 r.argument = o ? o.argument : null;
12633 doc = frame.contentWindow.document;
12635 doc = (frame.contentDocument || window.frames[id].document);
12637 if(doc && doc.body){
12638 r.responseText = doc.body.innerHTML;
12640 if(doc && doc.XMLDocument){
12641 r.responseXML = doc.XMLDocument;
12643 r.responseXML = doc;
12650 Roo.EventManager.removeListener(frame, 'load', cb, this);
12652 this.fireEvent("requestcomplete", this, r, o);
12653 Roo.callback(o.success, o.scope, [r, o]);
12654 Roo.callback(o.callback, o.scope, [o, true, r]);
12656 setTimeout(function(){document.body.removeChild(frame);}, 100);
12659 Roo.EventManager.on(frame, 'load', cb, this);
12662 if(hiddens){ // remove dynamic params
12663 for(var i = 0, len = hiddens.length; i < len; i++){
12664 form.removeChild(hiddens[i]);
12668 // this is a 'formdata version???'
12671 doFormDataUpload : function(o, url)
12675 var form = Roo.getDom(o.form);
12676 form.enctype = form.encoding = 'multipart/form-data';
12677 formData = o.formData === true ? new FormData(form) : o.formData;
12679 formData = o.formData === true ? new FormData() : o.formData;
12684 success: this.handleResponse,
12685 failure: this.handleFailure,
12687 argument: {options: o},
12688 timeout : o.timeout || this.timeout
12691 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12695 }else if(this.autoAbort !== false){
12699 //Roo.lib.Ajax.defaultPostHeader = null;
12700 Roo.lib.Ajax.useDefaultHeader = false;
12701 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
12702 Roo.lib.Ajax.useDefaultHeader = true;
12710 * Ext JS Library 1.1.1
12711 * Copyright(c) 2006-2007, Ext JS, LLC.
12713 * Originally Released Under LGPL - original licence link has changed is not relivant.
12716 * <script type="text/javascript">
12720 * Global Ajax request class.
12723 * @extends Roo.data.Connection
12726 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
12727 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12728 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
12729 * @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)
12730 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12731 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12732 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12734 Roo.Ajax = new Roo.data.Connection({
12743 * Serialize the passed form into a url encoded string
12745 * @param {String/HTMLElement} form
12748 serializeForm : function(form){
12749 return Roo.lib.Ajax.serializeForm(form);
12753 * Ext JS Library 1.1.1
12754 * Copyright(c) 2006-2007, Ext JS, LLC.
12756 * Originally Released Under LGPL - original licence link has changed is not relivant.
12759 * <script type="text/javascript">
12764 * @class Roo.UpdateManager
12765 * @extends Roo.util.Observable
12766 * Provides AJAX-style update for Element object.<br><br>
12769 * // Get it from a Roo.Element object
12770 * var el = Roo.get("foo");
12771 * var mgr = el.getUpdateManager();
12772 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
12774 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12776 * // or directly (returns the same UpdateManager instance)
12777 * var mgr = new Roo.UpdateManager("myElementId");
12778 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12779 * mgr.on("update", myFcnNeedsToKnow);
12781 // short handed call directly from the element object
12782 Roo.get("foo").load({
12786 text: "Loading Foo..."
12790 * Create new UpdateManager directly.
12791 * @param {String/HTMLElement/Roo.Element} el The element to update
12792 * @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).
12794 Roo.UpdateManager = function(el, forceNew){
12796 if(!forceNew && el.updateManager){
12797 return el.updateManager;
12800 * The Element object
12801 * @type Roo.Element
12805 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12808 this.defaultUrl = null;
12812 * @event beforeupdate
12813 * Fired before an update is made, return false from your handler and the update is cancelled.
12814 * @param {Roo.Element} el
12815 * @param {String/Object/Function} url
12816 * @param {String/Object} params
12818 "beforeupdate": true,
12821 * Fired after successful update is made.
12822 * @param {Roo.Element} el
12823 * @param {Object} oResponseObject The response Object
12828 * Fired on update failure.
12829 * @param {Roo.Element} el
12830 * @param {Object} oResponseObject The response Object
12834 var d = Roo.UpdateManager.defaults;
12836 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12839 this.sslBlankUrl = d.sslBlankUrl;
12841 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12844 this.disableCaching = d.disableCaching;
12846 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12849 this.indicatorText = d.indicatorText;
12851 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12854 this.showLoadIndicator = d.showLoadIndicator;
12856 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12859 this.timeout = d.timeout;
12862 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12865 this.loadScripts = d.loadScripts;
12868 * Transaction object of current executing transaction
12870 this.transaction = null;
12875 this.autoRefreshProcId = null;
12877 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12880 this.refreshDelegate = this.refresh.createDelegate(this);
12882 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12885 this.updateDelegate = this.update.createDelegate(this);
12887 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12890 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12894 this.successDelegate = this.processSuccess.createDelegate(this);
12898 this.failureDelegate = this.processFailure.createDelegate(this);
12900 if(!this.renderer){
12902 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12904 this.renderer = new Roo.UpdateManager.BasicRenderer();
12907 Roo.UpdateManager.superclass.constructor.call(this);
12910 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12912 * Get the Element this UpdateManager is bound to
12913 * @return {Roo.Element} The element
12915 getEl : function(){
12919 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12920 * @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:
12923 url: "your-url.php",<br/>
12924 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12925 callback: yourFunction,<br/>
12926 scope: yourObject, //(optional scope) <br/>
12927 discardUrl: false, <br/>
12928 nocache: false,<br/>
12929 text: "Loading...",<br/>
12931 scripts: false<br/>
12934 * The only required property is url. The optional properties nocache, text and scripts
12935 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12936 * @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}
12937 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12938 * @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.
12940 update : function(url, params, callback, discardUrl){
12941 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12942 var method = this.method,
12944 if(typeof url == "object"){ // must be config object
12947 params = params || cfg.params;
12948 callback = callback || cfg.callback;
12949 discardUrl = discardUrl || cfg.discardUrl;
12950 if(callback && cfg.scope){
12951 callback = callback.createDelegate(cfg.scope);
12953 if(typeof cfg.method != "undefined"){method = cfg.method;};
12954 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12955 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12956 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12957 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12959 this.showLoading();
12961 this.defaultUrl = url;
12963 if(typeof url == "function"){
12964 url = url.call(this);
12967 method = method || (params ? "POST" : "GET");
12968 if(method == "GET"){
12969 url = this.prepareUrl(url);
12972 var o = Roo.apply(cfg ||{}, {
12975 success: this.successDelegate,
12976 failure: this.failureDelegate,
12977 callback: undefined,
12978 timeout: (this.timeout*1000),
12979 argument: {"url": url, "form": null, "callback": callback, "params": params}
12981 Roo.log("updated manager called with timeout of " + o.timeout);
12982 this.transaction = Roo.Ajax.request(o);
12987 * 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.
12988 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12989 * @param {String/HTMLElement} form The form Id or form element
12990 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12991 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12992 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12994 formUpdate : function(form, url, reset, callback){
12995 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12996 if(typeof url == "function"){
12997 url = url.call(this);
12999 form = Roo.getDom(form);
13000 this.transaction = Roo.Ajax.request({
13003 success: this.successDelegate,
13004 failure: this.failureDelegate,
13005 timeout: (this.timeout*1000),
13006 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13008 this.showLoading.defer(1, this);
13013 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13014 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13016 refresh : function(callback){
13017 if(this.defaultUrl == null){
13020 this.update(this.defaultUrl, null, callback, true);
13024 * Set this element to auto refresh.
13025 * @param {Number} interval How often to update (in seconds).
13026 * @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)
13027 * @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}
13028 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13029 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13031 startAutoRefresh : function(interval, url, params, callback, refreshNow){
13033 this.update(url || this.defaultUrl, params, callback, true);
13035 if(this.autoRefreshProcId){
13036 clearInterval(this.autoRefreshProcId);
13038 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13042 * Stop auto refresh on this element.
13044 stopAutoRefresh : function(){
13045 if(this.autoRefreshProcId){
13046 clearInterval(this.autoRefreshProcId);
13047 delete this.autoRefreshProcId;
13051 isAutoRefreshing : function(){
13052 return this.autoRefreshProcId ? true : false;
13055 * Called to update the element to "Loading" state. Override to perform custom action.
13057 showLoading : function(){
13058 if(this.showLoadIndicator){
13059 this.el.update(this.indicatorText);
13064 * Adds unique parameter to query string if disableCaching = true
13067 prepareUrl : function(url){
13068 if(this.disableCaching){
13069 var append = "_dc=" + (new Date().getTime());
13070 if(url.indexOf("?") !== -1){
13071 url += "&" + append;
13073 url += "?" + append;
13082 processSuccess : function(response){
13083 this.transaction = null;
13084 if(response.argument.form && response.argument.reset){
13085 try{ // put in try/catch since some older FF releases had problems with this
13086 response.argument.form.reset();
13089 if(this.loadScripts){
13090 this.renderer.render(this.el, response, this,
13091 this.updateComplete.createDelegate(this, [response]));
13093 this.renderer.render(this.el, response, this);
13094 this.updateComplete(response);
13098 updateComplete : function(response){
13099 this.fireEvent("update", this.el, response);
13100 if(typeof response.argument.callback == "function"){
13101 response.argument.callback(this.el, true, response);
13108 processFailure : function(response){
13109 this.transaction = null;
13110 this.fireEvent("failure", this.el, response);
13111 if(typeof response.argument.callback == "function"){
13112 response.argument.callback(this.el, false, response);
13117 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13118 * @param {Object} renderer The object implementing the render() method
13120 setRenderer : function(renderer){
13121 this.renderer = renderer;
13124 getRenderer : function(){
13125 return this.renderer;
13129 * Set the defaultUrl used for updates
13130 * @param {String/Function} defaultUrl The url or a function to call to get the url
13132 setDefaultUrl : function(defaultUrl){
13133 this.defaultUrl = defaultUrl;
13137 * Aborts the executing transaction
13139 abort : function(){
13140 if(this.transaction){
13141 Roo.Ajax.abort(this.transaction);
13146 * Returns true if an update is in progress
13147 * @return {Boolean}
13149 isUpdating : function(){
13150 if(this.transaction){
13151 return Roo.Ajax.isLoading(this.transaction);
13158 * @class Roo.UpdateManager.defaults
13159 * @static (not really - but it helps the doc tool)
13160 * The defaults collection enables customizing the default properties of UpdateManager
13162 Roo.UpdateManager.defaults = {
13164 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13170 * True to process scripts by default (Defaults to false).
13173 loadScripts : false,
13176 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13179 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13181 * Whether to append unique parameter on get request to disable caching (Defaults to false).
13184 disableCaching : false,
13186 * Whether to show indicatorText when loading (Defaults to true).
13189 showLoadIndicator : true,
13191 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
13194 indicatorText : '<div class="loading-indicator">Loading...</div>'
13198 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13200 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13201 * @param {String/HTMLElement/Roo.Element} el The element to update
13202 * @param {String} url The url
13203 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13204 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13207 * @member Roo.UpdateManager
13209 Roo.UpdateManager.updateElement = function(el, url, params, options){
13210 var um = Roo.get(el, true).getUpdateManager();
13211 Roo.apply(um, options);
13212 um.update(url, params, options ? options.callback : null);
13214 // alias for backwards compat
13215 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13217 * @class Roo.UpdateManager.BasicRenderer
13218 * Default Content renderer. Updates the elements innerHTML with the responseText.
13220 Roo.UpdateManager.BasicRenderer = function(){};
13222 Roo.UpdateManager.BasicRenderer.prototype = {
13224 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13225 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13226 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13227 * @param {Roo.Element} el The element being rendered
13228 * @param {Object} response The YUI Connect response object
13229 * @param {UpdateManager} updateManager The calling update manager
13230 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13232 render : function(el, response, updateManager, callback){
13233 el.update(response.responseText, updateManager.loadScripts, callback);
13239 * (c)) Alan Knowles
13245 * @class Roo.DomTemplate
13246 * @extends Roo.Template
13247 * An effort at a dom based template engine..
13249 * Similar to XTemplate, except it uses dom parsing to create the template..
13251 * Supported features:
13256 {a_variable} - output encoded.
13257 {a_variable.format:("Y-m-d")} - call a method on the variable
13258 {a_variable:raw} - unencoded output
13259 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13260 {a_variable:this.method_on_template(...)} - call a method on the template object.
13265 <div roo-for="a_variable or condition.."></div>
13266 <div roo-if="a_variable or condition"></div>
13267 <div roo-exec="some javascript"></div>
13268 <div roo-name="named_template"></div>
13273 Roo.DomTemplate = function()
13275 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13282 Roo.extend(Roo.DomTemplate, Roo.Template, {
13284 * id counter for sub templates.
13288 * flag to indicate if dom parser is inside a pre,
13289 * it will strip whitespace if not.
13294 * The various sub templates
13302 * basic tag replacing syntax
13305 * // you can fake an object call by doing this
13309 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13310 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13312 iterChild : function (node, method) {
13314 var oldPre = this.inPre;
13315 if (node.tagName == 'PRE') {
13318 for( var i = 0; i < node.childNodes.length; i++) {
13319 method.call(this, node.childNodes[i]);
13321 this.inPre = oldPre;
13327 * compile the template
13329 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13332 compile: function()
13336 // covert the html into DOM...
13340 doc = document.implementation.createHTMLDocument("");
13341 doc.documentElement.innerHTML = this.html ;
13342 div = doc.documentElement;
13344 // old IE... - nasty -- it causes all sorts of issues.. with
13345 // images getting pulled from server..
13346 div = document.createElement('div');
13347 div.innerHTML = this.html;
13349 //doc.documentElement.innerHTML = htmlBody
13355 this.iterChild(div, function(n) {_t.compileNode(n, true); });
13357 var tpls = this.tpls;
13359 // create a top level template from the snippet..
13361 //Roo.log(div.innerHTML);
13368 body : div.innerHTML,
13381 Roo.each(tpls, function(tp){
13382 this.compileTpl(tp);
13383 this.tpls[tp.id] = tp;
13386 this.master = tpls[0];
13392 compileNode : function(node, istop) {
13397 // skip anything not a tag..
13398 if (node.nodeType != 1) {
13399 if (node.nodeType == 3 && !this.inPre) {
13400 // reduce white space..
13401 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
13424 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13425 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13426 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13427 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13433 // just itterate children..
13434 this.iterChild(node,this.compileNode);
13437 tpl.uid = this.id++;
13438 tpl.value = node.getAttribute('roo-' + tpl.attr);
13439 node.removeAttribute('roo-'+ tpl.attr);
13440 if (tpl.attr != 'name') {
13441 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13442 node.parentNode.replaceChild(placeholder, node);
13445 var placeholder = document.createElement('span');
13446 placeholder.className = 'roo-tpl-' + tpl.value;
13447 node.parentNode.replaceChild(placeholder, node);
13450 // parent now sees '{domtplXXXX}
13451 this.iterChild(node,this.compileNode);
13453 // we should now have node body...
13454 var div = document.createElement('div');
13455 div.appendChild(node);
13457 // this has the unfortunate side effect of converting tagged attributes
13458 // eg. href="{...}" into %7C...%7D
13459 // this has been fixed by searching for those combo's although it's a bit hacky..
13462 tpl.body = div.innerHTML;
13469 switch (tpl.value) {
13470 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13471 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13472 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13477 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13481 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13485 tpl.id = tpl.value; // replace non characters???
13491 this.tpls.push(tpl);
13501 * Compile a segment of the template into a 'sub-template'
13507 compileTpl : function(tpl)
13509 var fm = Roo.util.Format;
13510 var useF = this.disableFormats !== true;
13512 var sep = Roo.isGecko ? "+\n" : ",\n";
13514 var undef = function(str) {
13515 Roo.debug && Roo.log("Property not found :" + str);
13519 //Roo.log(tpl.body);
13523 var fn = function(m, lbrace, name, format, args)
13526 //Roo.log(arguments);
13527 args = args ? args.replace(/\\'/g,"'") : args;
13528 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13529 if (typeof(format) == 'undefined') {
13530 format = 'htmlEncode';
13532 if (format == 'raw' ) {
13536 if(name.substr(0, 6) == 'domtpl'){
13537 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13540 // build an array of options to determine if value is undefined..
13542 // basically get 'xxxx.yyyy' then do
13543 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13544 // (function () { Roo.log("Property not found"); return ''; })() :
13549 Roo.each(name.split('.'), function(st) {
13550 lookfor += (lookfor.length ? '.': '') + st;
13551 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
13554 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13557 if(format && useF){
13559 args = args ? ',' + args : "";
13561 if(format.substr(0, 5) != "this."){
13562 format = "fm." + format + '(';
13564 format = 'this.call("'+ format.substr(5) + '", ';
13568 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
13571 if (args && args.length) {
13572 // called with xxyx.yuu:(test,test)
13574 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
13576 // raw.. - :raw modifier..
13577 return "'"+ sep + udef_st + name + ")"+sep+"'";
13581 // branched to use + in gecko and [].join() in others
13583 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
13584 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13587 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
13588 body.push(tpl.body.replace(/(\r\n|\n)/g,
13589 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13590 body.push("'].join('');};};");
13591 body = body.join('');
13594 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13596 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
13603 * same as applyTemplate, except it's done to one of the subTemplates
13604 * when using named templates, you can do:
13606 * var str = pl.applySubTemplate('your-name', values);
13609 * @param {Number} id of the template
13610 * @param {Object} values to apply to template
13611 * @param {Object} parent (normaly the instance of this object)
13613 applySubTemplate : function(id, values, parent)
13617 var t = this.tpls[id];
13621 if(t.ifCall && !t.ifCall.call(this, values, parent)){
13622 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
13626 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
13633 if(t.execCall && t.execCall.call(this, values, parent)){
13637 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13643 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
13644 parent = t.target ? values : parent;
13645 if(t.forCall && vs instanceof Array){
13647 for(var i = 0, len = vs.length; i < len; i++){
13649 buf[buf.length] = t.compiled.call(this, vs[i], parent);
13651 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13653 //Roo.log(t.compiled);
13657 return buf.join('');
13660 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13665 return t.compiled.call(this, vs, parent);
13667 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13669 //Roo.log(t.compiled);
13677 applyTemplate : function(values){
13678 return this.master.compiled.call(this, values, {});
13679 //var s = this.subs;
13682 apply : function(){
13683 return this.applyTemplate.apply(this, arguments);
13688 Roo.DomTemplate.from = function(el){
13689 el = Roo.getDom(el);
13690 return new Roo.Domtemplate(el.value || el.innerHTML);
13693 * Ext JS Library 1.1.1
13694 * Copyright(c) 2006-2007, Ext JS, LLC.
13696 * Originally Released Under LGPL - original licence link has changed is not relivant.
13699 * <script type="text/javascript">
13703 * @class Roo.util.DelayedTask
13704 * Provides a convenient method of performing setTimeout where a new
13705 * timeout cancels the old timeout. An example would be performing validation on a keypress.
13706 * You can use this class to buffer
13707 * the keypress events for a certain number of milliseconds, and perform only if they stop
13708 * for that amount of time.
13709 * @constructor The parameters to this constructor serve as defaults and are not required.
13710 * @param {Function} fn (optional) The default function to timeout
13711 * @param {Object} scope (optional) The default scope of that timeout
13712 * @param {Array} args (optional) The default Array of arguments
13714 Roo.util.DelayedTask = function(fn, scope, args){
13715 var id = null, d, t;
13717 var call = function(){
13718 var now = new Date().getTime();
13722 fn.apply(scope, args || []);
13726 * Cancels any pending timeout and queues a new one
13727 * @param {Number} delay The milliseconds to delay
13728 * @param {Function} newFn (optional) Overrides function passed to constructor
13729 * @param {Object} newScope (optional) Overrides scope passed to constructor
13730 * @param {Array} newArgs (optional) Overrides args passed to constructor
13732 this.delay = function(delay, newFn, newScope, newArgs){
13733 if(id && delay != d){
13737 t = new Date().getTime();
13739 scope = newScope || scope;
13740 args = newArgs || args;
13742 id = setInterval(call, d);
13747 * Cancel the last queued timeout
13749 this.cancel = function(){
13757 * Ext JS Library 1.1.1
13758 * Copyright(c) 2006-2007, Ext JS, LLC.
13760 * Originally Released Under LGPL - original licence link has changed is not relivant.
13763 * <script type="text/javascript">
13766 * @class Roo.util.TaskRunner
13767 * Manage background tasks - not sure why this is better that setInterval?
13772 Roo.util.TaskRunner = function(interval){
13773 interval = interval || 10;
13774 var tasks = [], removeQueue = [];
13776 var running = false;
13778 var stopThread = function(){
13784 var startThread = function(){
13787 id = setInterval(runTasks, interval);
13791 var removeTask = function(task){
13792 removeQueue.push(task);
13798 var runTasks = function(){
13799 if(removeQueue.length > 0){
13800 for(var i = 0, len = removeQueue.length; i < len; i++){
13801 tasks.remove(removeQueue[i]);
13804 if(tasks.length < 1){
13809 var now = new Date().getTime();
13810 for(var i = 0, len = tasks.length; i < len; ++i){
13812 var itime = now - t.taskRunTime;
13813 if(t.interval <= itime){
13814 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13815 t.taskRunTime = now;
13816 if(rt === false || t.taskRunCount === t.repeat){
13821 if(t.duration && t.duration <= (now - t.taskStartTime)){
13828 * Queues a new task.
13829 * @param {Object} task
13831 * Task property : interval = how frequent to run.
13832 * Task object should implement
13834 * Task object may implement
13835 * function onStop()
13837 this.start = function(task){
13839 task.taskStartTime = new Date().getTime();
13840 task.taskRunTime = 0;
13841 task.taskRunCount = 0;
13847 * @param {Object} task
13849 this.stop = function(task){
13856 this.stopAll = function(){
13858 for(var i = 0, len = tasks.length; i < len; i++){
13859 if(tasks[i].onStop){
13868 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13870 * Ext JS Library 1.1.1
13871 * Copyright(c) 2006-2007, Ext JS, LLC.
13873 * Originally Released Under LGPL - original licence link has changed is not relivant.
13876 * <script type="text/javascript">
13881 * @class Roo.util.MixedCollection
13882 * @extends Roo.util.Observable
13883 * A Collection class that maintains both numeric indexes and keys and exposes events.
13885 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13886 * collection (defaults to false)
13887 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13888 * and return the key value for that item. This is used when available to look up the key on items that
13889 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13890 * equivalent to providing an implementation for the {@link #getKey} method.
13892 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13900 * Fires when the collection is cleared.
13905 * Fires when an item is added to the collection.
13906 * @param {Number} index The index at which the item was added.
13907 * @param {Object} o The item added.
13908 * @param {String} key The key associated with the added item.
13913 * Fires when an item is replaced in the collection.
13914 * @param {String} key he key associated with the new added.
13915 * @param {Object} old The item being replaced.
13916 * @param {Object} new The new item.
13921 * Fires when an item is removed from the collection.
13922 * @param {Object} o The item being removed.
13923 * @param {String} key (optional) The key associated with the removed item.
13928 this.allowFunctions = allowFunctions === true;
13930 this.getKey = keyFn;
13932 Roo.util.MixedCollection.superclass.constructor.call(this);
13935 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13936 allowFunctions : false,
13939 * Adds an item to the collection.
13940 * @param {String} key The key to associate with the item
13941 * @param {Object} o The item to add.
13942 * @return {Object} The item added.
13944 add : function(key, o){
13945 if(arguments.length == 1){
13947 key = this.getKey(o);
13949 if(typeof key == "undefined" || key === null){
13951 this.items.push(o);
13952 this.keys.push(null);
13954 var old = this.map[key];
13956 return this.replace(key, o);
13959 this.items.push(o);
13961 this.keys.push(key);
13963 this.fireEvent("add", this.length-1, o, key);
13968 * MixedCollection has a generic way to fetch keys if you implement getKey.
13971 var mc = new Roo.util.MixedCollection();
13972 mc.add(someEl.dom.id, someEl);
13973 mc.add(otherEl.dom.id, otherEl);
13977 var mc = new Roo.util.MixedCollection();
13978 mc.getKey = function(el){
13984 // or via the constructor
13985 var mc = new Roo.util.MixedCollection(false, function(el){
13991 * @param o {Object} The item for which to find the key.
13992 * @return {Object} The key for the passed item.
13994 getKey : function(o){
13999 * Replaces an item in the collection.
14000 * @param {String} key The key associated with the item to replace, or the item to replace.
14001 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14002 * @return {Object} The new item.
14004 replace : function(key, o){
14005 if(arguments.length == 1){
14007 key = this.getKey(o);
14009 var old = this.item(key);
14010 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14011 return this.add(key, o);
14013 var index = this.indexOfKey(key);
14014 this.items[index] = o;
14016 this.fireEvent("replace", key, old, o);
14021 * Adds all elements of an Array or an Object to the collection.
14022 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14023 * an Array of values, each of which are added to the collection.
14025 addAll : function(objs){
14026 if(arguments.length > 1 || objs instanceof Array){
14027 var args = arguments.length > 1 ? arguments : objs;
14028 for(var i = 0, len = args.length; i < len; i++){
14032 for(var key in objs){
14033 if(this.allowFunctions || typeof objs[key] != "function"){
14034 this.add(key, objs[key]);
14041 * Executes the specified function once for every item in the collection, passing each
14042 * item as the first and only parameter. returning false from the function will stop the iteration.
14043 * @param {Function} fn The function to execute for each item.
14044 * @param {Object} scope (optional) The scope in which to execute the function.
14046 each : function(fn, scope){
14047 var items = [].concat(this.items); // each safe for removal
14048 for(var i = 0, len = items.length; i < len; i++){
14049 if(fn.call(scope || items[i], items[i], i, len) === false){
14056 * Executes the specified function once for every key in the collection, passing each
14057 * key, and its associated item as the first two parameters.
14058 * @param {Function} fn The function to execute for each item.
14059 * @param {Object} scope (optional) The scope in which to execute the function.
14061 eachKey : function(fn, scope){
14062 for(var i = 0, len = this.keys.length; i < len; i++){
14063 fn.call(scope || window, this.keys[i], this.items[i], i, len);
14068 * Returns the first item in the collection which elicits a true return value from the
14069 * passed selection function.
14070 * @param {Function} fn The selection function to execute for each item.
14071 * @param {Object} scope (optional) The scope in which to execute the function.
14072 * @return {Object} The first item in the collection which returned true from the selection function.
14074 find : function(fn, scope){
14075 for(var i = 0, len = this.items.length; i < len; i++){
14076 if(fn.call(scope || window, this.items[i], this.keys[i])){
14077 return this.items[i];
14084 * Inserts an item at the specified index in the collection.
14085 * @param {Number} index The index to insert the item at.
14086 * @param {String} key The key to associate with the new item, or the item itself.
14087 * @param {Object} o (optional) If the second parameter was a key, the new item.
14088 * @return {Object} The item inserted.
14090 insert : function(index, key, o){
14091 if(arguments.length == 2){
14093 key = this.getKey(o);
14095 if(index >= this.length){
14096 return this.add(key, o);
14099 this.items.splice(index, 0, o);
14100 if(typeof key != "undefined" && key != null){
14103 this.keys.splice(index, 0, key);
14104 this.fireEvent("add", index, o, key);
14109 * Removed an item from the collection.
14110 * @param {Object} o The item to remove.
14111 * @return {Object} The item removed.
14113 remove : function(o){
14114 return this.removeAt(this.indexOf(o));
14118 * Remove an item from a specified index in the collection.
14119 * @param {Number} index The index within the collection of the item to remove.
14121 removeAt : function(index){
14122 if(index < this.length && index >= 0){
14124 var o = this.items[index];
14125 this.items.splice(index, 1);
14126 var key = this.keys[index];
14127 if(typeof key != "undefined"){
14128 delete this.map[key];
14130 this.keys.splice(index, 1);
14131 this.fireEvent("remove", o, key);
14136 * Removed an item associated with the passed key fom the collection.
14137 * @param {String} key The key of the item to remove.
14139 removeKey : function(key){
14140 return this.removeAt(this.indexOfKey(key));
14144 * Returns the number of items in the collection.
14145 * @return {Number} the number of items in the collection.
14147 getCount : function(){
14148 return this.length;
14152 * Returns index within the collection of the passed Object.
14153 * @param {Object} o The item to find the index of.
14154 * @return {Number} index of the item.
14156 indexOf : function(o){
14157 if(!this.items.indexOf){
14158 for(var i = 0, len = this.items.length; i < len; i++){
14159 if(this.items[i] == o) {
14165 return this.items.indexOf(o);
14170 * Returns index within the collection of the passed key.
14171 * @param {String} key The key to find the index of.
14172 * @return {Number} index of the key.
14174 indexOfKey : function(key){
14175 if(!this.keys.indexOf){
14176 for(var i = 0, len = this.keys.length; i < len; i++){
14177 if(this.keys[i] == key) {
14183 return this.keys.indexOf(key);
14188 * Returns the item associated with the passed key OR index. Key has priority over index.
14189 * @param {String/Number} key The key or index of the item.
14190 * @return {Object} The item associated with the passed key.
14192 item : function(key){
14193 if (key === 'length') {
14196 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14197 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14201 * Returns the item at the specified index.
14202 * @param {Number} index The index of the item.
14205 itemAt : function(index){
14206 return this.items[index];
14210 * Returns the item associated with the passed key.
14211 * @param {String/Number} key The key of the item.
14212 * @return {Object} The item associated with the passed key.
14214 key : function(key){
14215 return this.map[key];
14219 * Returns true if the collection contains the passed Object as an item.
14220 * @param {Object} o The Object to look for in the collection.
14221 * @return {Boolean} True if the collection contains the Object as an item.
14223 contains : function(o){
14224 return this.indexOf(o) != -1;
14228 * Returns true if the collection contains the passed Object as a key.
14229 * @param {String} key The key to look for in the collection.
14230 * @return {Boolean} True if the collection contains the Object as a key.
14232 containsKey : function(key){
14233 return typeof this.map[key] != "undefined";
14237 * Removes all items from the collection.
14239 clear : function(){
14244 this.fireEvent("clear");
14248 * Returns the first item in the collection.
14249 * @return {Object} the first item in the collection..
14251 first : function(){
14252 return this.items[0];
14256 * Returns the last item in the collection.
14257 * @return {Object} the last item in the collection..
14260 return this.items[this.length-1];
14263 _sort : function(property, dir, fn){
14264 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14265 fn = fn || function(a, b){
14268 var c = [], k = this.keys, items = this.items;
14269 for(var i = 0, len = items.length; i < len; i++){
14270 c[c.length] = {key: k[i], value: items[i], index: i};
14272 c.sort(function(a, b){
14273 var v = fn(a[property], b[property]) * dsc;
14275 v = (a.index < b.index ? -1 : 1);
14279 for(var i = 0, len = c.length; i < len; i++){
14280 items[i] = c[i].value;
14283 this.fireEvent("sort", this);
14287 * Sorts this collection with the passed comparison function
14288 * @param {String} direction (optional) "ASC" or "DESC"
14289 * @param {Function} fn (optional) comparison function
14291 sort : function(dir, fn){
14292 this._sort("value", dir, fn);
14296 * Sorts this collection by keys
14297 * @param {String} direction (optional) "ASC" or "DESC"
14298 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14300 keySort : function(dir, fn){
14301 this._sort("key", dir, fn || function(a, b){
14302 return String(a).toUpperCase()-String(b).toUpperCase();
14307 * Returns a range of items in this collection
14308 * @param {Number} startIndex (optional) defaults to 0
14309 * @param {Number} endIndex (optional) default to the last item
14310 * @return {Array} An array of items
14312 getRange : function(start, end){
14313 var items = this.items;
14314 if(items.length < 1){
14317 start = start || 0;
14318 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14321 for(var i = start; i <= end; i++) {
14322 r[r.length] = items[i];
14325 for(var i = start; i >= end; i--) {
14326 r[r.length] = items[i];
14333 * Filter the <i>objects</i> in this collection by a specific property.
14334 * Returns a new collection that has been filtered.
14335 * @param {String} property A property on your objects
14336 * @param {String/RegExp} value Either string that the property values
14337 * should start with or a RegExp to test against the property
14338 * @return {MixedCollection} The new filtered collection
14340 filter : function(property, value){
14341 if(!value.exec){ // not a regex
14342 value = String(value);
14343 if(value.length == 0){
14344 return this.clone();
14346 value = new RegExp("^" + Roo.escapeRe(value), "i");
14348 return this.filterBy(function(o){
14349 return o && value.test(o[property]);
14354 * Filter by a function. * Returns a new collection that has been filtered.
14355 * The passed function will be called with each
14356 * object in the collection. If the function returns true, the value is included
14357 * otherwise it is filtered.
14358 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14359 * @param {Object} scope (optional) The scope of the function (defaults to this)
14360 * @return {MixedCollection} The new filtered collection
14362 filterBy : function(fn, scope){
14363 var r = new Roo.util.MixedCollection();
14364 r.getKey = this.getKey;
14365 var k = this.keys, it = this.items;
14366 for(var i = 0, len = it.length; i < len; i++){
14367 if(fn.call(scope||this, it[i], k[i])){
14368 r.add(k[i], it[i]);
14375 * Creates a duplicate of this collection
14376 * @return {MixedCollection}
14378 clone : function(){
14379 var r = new Roo.util.MixedCollection();
14380 var k = this.keys, it = this.items;
14381 for(var i = 0, len = it.length; i < len; i++){
14382 r.add(k[i], it[i]);
14384 r.getKey = this.getKey;
14389 * Returns the item associated with the passed key or index.
14391 * @param {String/Number} key The key or index of the item.
14392 * @return {Object} The item associated with the passed key.
14394 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14396 * Ext JS Library 1.1.1
14397 * Copyright(c) 2006-2007, Ext JS, LLC.
14399 * Originally Released Under LGPL - original licence link has changed is not relivant.
14402 * <script type="text/javascript">
14405 * @class Roo.util.JSON
14406 * Modified version of Douglas Crockford"s json.js that doesn"t
14407 * mess with the Object prototype
14408 * http://www.json.org/js.html
14411 Roo.util.JSON = new (function(){
14412 var useHasOwn = {}.hasOwnProperty ? true : false;
14414 // crashes Safari in some instances
14415 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14417 var pad = function(n) {
14418 return n < 10 ? "0" + n : n;
14431 var encodeString = function(s){
14432 if (/["\\\x00-\x1f]/.test(s)) {
14433 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14438 c = b.charCodeAt();
14440 Math.floor(c / 16).toString(16) +
14441 (c % 16).toString(16);
14444 return '"' + s + '"';
14447 var encodeArray = function(o){
14448 var a = ["["], b, i, l = o.length, v;
14449 for (i = 0; i < l; i += 1) {
14451 switch (typeof v) {
14460 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14468 var encodeDate = function(o){
14469 return '"' + o.getFullYear() + "-" +
14470 pad(o.getMonth() + 1) + "-" +
14471 pad(o.getDate()) + "T" +
14472 pad(o.getHours()) + ":" +
14473 pad(o.getMinutes()) + ":" +
14474 pad(o.getSeconds()) + '"';
14478 * Encodes an Object, Array or other value
14479 * @param {Mixed} o The variable to encode
14480 * @return {String} The JSON string
14482 this.encode = function(o)
14484 // should this be extended to fully wrap stringify..
14486 if(typeof o == "undefined" || o === null){
14488 }else if(o instanceof Array){
14489 return encodeArray(o);
14490 }else if(o instanceof Date){
14491 return encodeDate(o);
14492 }else if(typeof o == "string"){
14493 return encodeString(o);
14494 }else if(typeof o == "number"){
14495 return isFinite(o) ? String(o) : "null";
14496 }else if(typeof o == "boolean"){
14499 var a = ["{"], b, i, v;
14501 if(!useHasOwn || o.hasOwnProperty(i)) {
14503 switch (typeof v) {
14512 a.push(this.encode(i), ":",
14513 v === null ? "null" : this.encode(v));
14524 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14525 * @param {String} json The JSON string
14526 * @return {Object} The resulting object
14528 this.decode = function(json){
14530 return /** eval:var:json */ eval("(" + json + ')');
14534 * Shorthand for {@link Roo.util.JSON#encode}
14535 * @member Roo encode
14537 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14539 * Shorthand for {@link Roo.util.JSON#decode}
14540 * @member Roo decode
14542 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14545 * Ext JS Library 1.1.1
14546 * Copyright(c) 2006-2007, Ext JS, LLC.
14548 * Originally Released Under LGPL - original licence link has changed is not relivant.
14551 * <script type="text/javascript">
14555 * @class Roo.util.Format
14556 * Reusable data formatting functions
14559 Roo.util.Format = function(){
14560 var trimRe = /^\s+|\s+$/g;
14563 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14564 * @param {String} value The string to truncate
14565 * @param {Number} length The maximum length to allow before truncating
14566 * @return {String} The converted text
14568 ellipsis : function(value, len){
14569 if(value && value.length > len){
14570 return value.substr(0, len-3)+"...";
14576 * Checks a reference and converts it to empty string if it is undefined
14577 * @param {Mixed} value Reference to check
14578 * @return {Mixed} Empty string if converted, otherwise the original value
14580 undef : function(value){
14581 return typeof value != "undefined" ? value : "";
14585 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14586 * @param {String} value The string to encode
14587 * @return {String} The encoded text
14589 htmlEncode : function(value){
14590 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
14594 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14595 * @param {String} value The string to decode
14596 * @return {String} The decoded text
14598 htmlDecode : function(value){
14599 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
14603 * Trims any whitespace from either side of a string
14604 * @param {String} value The text to trim
14605 * @return {String} The trimmed text
14607 trim : function(value){
14608 return String(value).replace(trimRe, "");
14612 * Returns a substring from within an original string
14613 * @param {String} value The original text
14614 * @param {Number} start The start index of the substring
14615 * @param {Number} length The length of the substring
14616 * @return {String} The substring
14618 substr : function(value, start, length){
14619 return String(value).substr(start, length);
14623 * Converts a string to all lower case letters
14624 * @param {String} value The text to convert
14625 * @return {String} The converted text
14627 lowercase : function(value){
14628 return String(value).toLowerCase();
14632 * Converts a string to all upper case letters
14633 * @param {String} value The text to convert
14634 * @return {String} The converted text
14636 uppercase : function(value){
14637 return String(value).toUpperCase();
14641 * Converts the first character only of a string to upper case
14642 * @param {String} value The text to convert
14643 * @return {String} The converted text
14645 capitalize : function(value){
14646 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
14650 call : function(value, fn){
14651 if(arguments.length > 2){
14652 var args = Array.prototype.slice.call(arguments, 2);
14653 args.unshift(value);
14655 return /** eval:var:value */ eval(fn).apply(window, args);
14657 /** eval:var:value */
14658 return /** eval:var:value */ eval(fn).call(window, value);
14664 * safer version of Math.toFixed..??/
14665 * @param {Number/String} value The numeric value to format
14666 * @param {Number/String} value Decimal places
14667 * @return {String} The formatted currency string
14669 toFixed : function(v, n)
14671 // why not use to fixed - precision is buggered???
14673 return Math.round(v-0);
14675 var fact = Math.pow(10,n+1);
14676 v = (Math.round((v-0)*fact))/fact;
14677 var z = (''+fact).substring(2);
14678 if (v == Math.floor(v)) {
14679 return Math.floor(v) + '.' + z;
14682 // now just padd decimals..
14683 var ps = String(v).split('.');
14684 var fd = (ps[1] + z);
14685 var r = fd.substring(0,n);
14686 var rm = fd.substring(n);
14688 return ps[0] + '.' + r;
14690 r*=1; // turn it into a number;
14692 if (String(r).length != n) {
14695 r = String(r).substring(1); // chop the end off.
14698 return ps[0] + '.' + r;
14703 * Format a number as US currency
14704 * @param {Number/String} value The numeric value to format
14705 * @return {String} The formatted currency string
14707 usMoney : function(v){
14708 return '$' + Roo.util.Format.number(v);
14713 * eventually this should probably emulate php's number_format
14714 * @param {Number/String} value The numeric value to format
14715 * @param {Number} decimals number of decimal places
14716 * @param {String} delimiter for thousands (default comma)
14717 * @return {String} The formatted currency string
14719 number : function(v, decimals, thousandsDelimiter)
14721 // multiply and round.
14722 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14723 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14725 var mul = Math.pow(10, decimals);
14726 var zero = String(mul).substring(1);
14727 v = (Math.round((v-0)*mul))/mul;
14729 // if it's '0' number.. then
14731 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14733 var ps = v.split('.');
14736 var r = /(\d+)(\d{3})/;
14739 if(thousandsDelimiter.length != 0) {
14740 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14745 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14746 // does not have decimals
14747 (decimals ? ('.' + zero) : '');
14750 return whole + sub ;
14754 * Parse a value into a formatted date using the specified format pattern.
14755 * @param {Mixed} value The value to format
14756 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14757 * @return {String} The formatted date string
14759 date : function(v, format){
14763 if(!(v instanceof Date)){
14764 v = new Date(Date.parse(v));
14766 return v.dateFormat(format || Roo.util.Format.defaults.date);
14770 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14771 * @param {String} format Any valid date format string
14772 * @return {Function} The date formatting function
14774 dateRenderer : function(format){
14775 return function(v){
14776 return Roo.util.Format.date(v, format);
14781 stripTagsRE : /<\/?[^>]+>/gi,
14784 * Strips all HTML tags
14785 * @param {Mixed} value The text from which to strip tags
14786 * @return {String} The stripped text
14788 stripTags : function(v){
14789 return !v ? v : String(v).replace(this.stripTagsRE, "");
14793 * Size in Mb,Gb etc.
14794 * @param {Number} value The number to be formated
14795 * @param {number} decimals how many decimal places
14796 * @return {String} the formated string
14798 size : function(value, decimals)
14800 var sizes = ['b', 'k', 'M', 'G', 'T'];
14804 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14805 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
14812 Roo.util.Format.defaults = {
14816 * Ext JS Library 1.1.1
14817 * Copyright(c) 2006-2007, Ext JS, LLC.
14819 * Originally Released Under LGPL - original licence link has changed is not relivant.
14822 * <script type="text/javascript">
14829 * @class Roo.MasterTemplate
14830 * @extends Roo.Template
14831 * Provides a template that can have child templates. The syntax is:
14833 var t = new Roo.MasterTemplate(
14834 '<select name="{name}">',
14835 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14838 t.add('options', {value: 'foo', text: 'bar'});
14839 // or you can add multiple child elements in one shot
14840 t.addAll('options', [
14841 {value: 'foo', text: 'bar'},
14842 {value: 'foo2', text: 'bar2'},
14843 {value: 'foo3', text: 'bar3'}
14845 // then append, applying the master template values
14846 t.append('my-form', {name: 'my-select'});
14848 * A name attribute for the child template is not required if you have only one child
14849 * template or you want to refer to them by index.
14851 Roo.MasterTemplate = function(){
14852 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14853 this.originalHtml = this.html;
14855 var m, re = this.subTemplateRe;
14858 while(m = re.exec(this.html)){
14859 var name = m[1], content = m[2];
14864 tpl : new Roo.Template(content)
14867 st[name] = st[subIndex];
14869 st[subIndex].tpl.compile();
14870 st[subIndex].tpl.call = this.call.createDelegate(this);
14873 this.subCount = subIndex;
14876 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14878 * The regular expression used to match sub templates
14882 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14885 * Applies the passed values to a child template.
14886 * @param {String/Number} name (optional) The name or index of the child template
14887 * @param {Array/Object} values The values to be applied to the template
14888 * @return {MasterTemplate} this
14890 add : function(name, values){
14891 if(arguments.length == 1){
14892 values = arguments[0];
14895 var s = this.subs[name];
14896 s.buffer[s.buffer.length] = s.tpl.apply(values);
14901 * Applies all the passed values to a child template.
14902 * @param {String/Number} name (optional) The name or index of the child template
14903 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14904 * @param {Boolean} reset (optional) True to reset the template first
14905 * @return {MasterTemplate} this
14907 fill : function(name, values, reset){
14909 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14917 for(var i = 0, len = values.length; i < len; i++){
14918 this.add(name, values[i]);
14924 * Resets the template for reuse
14925 * @return {MasterTemplate} this
14927 reset : function(){
14929 for(var i = 0; i < this.subCount; i++){
14935 applyTemplate : function(values){
14937 var replaceIndex = -1;
14938 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14939 return s[++replaceIndex].buffer.join("");
14941 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14944 apply : function(){
14945 return this.applyTemplate.apply(this, arguments);
14948 compile : function(){return this;}
14952 * Alias for fill().
14955 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14957 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14958 * var tpl = Roo.MasterTemplate.from('element-id');
14959 * @param {String/HTMLElement} el
14960 * @param {Object} config
14963 Roo.MasterTemplate.from = function(el, config){
14964 el = Roo.getDom(el);
14965 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14968 * Ext JS Library 1.1.1
14969 * Copyright(c) 2006-2007, Ext JS, LLC.
14971 * Originally Released Under LGPL - original licence link has changed is not relivant.
14974 * <script type="text/javascript">
14979 * @class Roo.util.CSS
14980 * Utility class for manipulating CSS rules
14984 Roo.util.CSS = function(){
14986 var doc = document;
14988 var camelRe = /(-[a-z])/gi;
14989 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14993 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14994 * tag and appended to the HEAD of the document.
14995 * @param {String|Object} cssText The text containing the css rules
14996 * @param {String} id An id to add to the stylesheet for later removal
14997 * @return {StyleSheet}
14999 createStyleSheet : function(cssText, id){
15001 var head = doc.getElementsByTagName("head")[0];
15002 var nrules = doc.createElement("style");
15003 nrules.setAttribute("type", "text/css");
15005 nrules.setAttribute("id", id);
15007 if (typeof(cssText) != 'string') {
15008 // support object maps..
15009 // not sure if this a good idea..
15010 // perhaps it should be merged with the general css handling
15011 // and handle js style props.
15012 var cssTextNew = [];
15013 for(var n in cssText) {
15015 for(var k in cssText[n]) {
15016 citems.push( k + ' : ' +cssText[n][k] + ';' );
15018 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15021 cssText = cssTextNew.join("\n");
15027 head.appendChild(nrules);
15028 ss = nrules.styleSheet;
15029 ss.cssText = cssText;
15032 nrules.appendChild(doc.createTextNode(cssText));
15034 nrules.cssText = cssText;
15036 head.appendChild(nrules);
15037 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15039 this.cacheStyleSheet(ss);
15044 * Removes a style or link tag by id
15045 * @param {String} id The id of the tag
15047 removeStyleSheet : function(id){
15048 var existing = doc.getElementById(id);
15050 existing.parentNode.removeChild(existing);
15055 * Dynamically swaps an existing stylesheet reference for a new one
15056 * @param {String} id The id of an existing link tag to remove
15057 * @param {String} url The href of the new stylesheet to include
15059 swapStyleSheet : function(id, url){
15060 this.removeStyleSheet(id);
15061 var ss = doc.createElement("link");
15062 ss.setAttribute("rel", "stylesheet");
15063 ss.setAttribute("type", "text/css");
15064 ss.setAttribute("id", id);
15065 ss.setAttribute("href", url);
15066 doc.getElementsByTagName("head")[0].appendChild(ss);
15070 * Refresh the rule cache if you have dynamically added stylesheets
15071 * @return {Object} An object (hash) of rules indexed by selector
15073 refreshCache : function(){
15074 return this.getRules(true);
15078 cacheStyleSheet : function(stylesheet){
15082 try{// try catch for cross domain access issue
15083 var ssRules = stylesheet.cssRules || stylesheet.rules;
15084 for(var j = ssRules.length-1; j >= 0; --j){
15085 rules[ssRules[j].selectorText] = ssRules[j];
15091 * Gets all css rules for the document
15092 * @param {Boolean} refreshCache true to refresh the internal cache
15093 * @return {Object} An object (hash) of rules indexed by selector
15095 getRules : function(refreshCache){
15096 if(rules == null || refreshCache){
15098 var ds = doc.styleSheets;
15099 for(var i =0, len = ds.length; i < len; i++){
15101 this.cacheStyleSheet(ds[i]);
15109 * Gets an an individual CSS rule by selector(s)
15110 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15111 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15112 * @return {CSSRule} The CSS rule or null if one is not found
15114 getRule : function(selector, refreshCache){
15115 var rs = this.getRules(refreshCache);
15116 if(!(selector instanceof Array)){
15117 return rs[selector];
15119 for(var i = 0; i < selector.length; i++){
15120 if(rs[selector[i]]){
15121 return rs[selector[i]];
15129 * Updates a rule property
15130 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15131 * @param {String} property The css property
15132 * @param {String} value The new value for the property
15133 * @return {Boolean} true If a rule was found and updated
15135 updateRule : function(selector, property, value){
15136 if(!(selector instanceof Array)){
15137 var rule = this.getRule(selector);
15139 rule.style[property.replace(camelRe, camelFn)] = value;
15143 for(var i = 0; i < selector.length; i++){
15144 if(this.updateRule(selector[i], property, value)){
15154 * Ext JS Library 1.1.1
15155 * Copyright(c) 2006-2007, Ext JS, LLC.
15157 * Originally Released Under LGPL - original licence link has changed is not relivant.
15160 * <script type="text/javascript">
15166 * @class Roo.util.ClickRepeater
15167 * @extends Roo.util.Observable
15169 * A wrapper class which can be applied to any element. Fires a "click" event while the
15170 * mouse is pressed. The interval between firings may be specified in the config but
15171 * defaults to 10 milliseconds.
15173 * Optionally, a CSS class may be applied to the element during the time it is pressed.
15175 * @cfg {String/HTMLElement/Element} el The element to act as a button.
15176 * @cfg {Number} delay The initial delay before the repeating event begins firing.
15177 * Similar to an autorepeat key delay.
15178 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15179 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15180 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15181 * "interval" and "delay" are ignored. "immediate" is honored.
15182 * @cfg {Boolean} preventDefault True to prevent the default click event
15183 * @cfg {Boolean} stopDefault True to stop the default click event
15186 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
15187 * 2007-02-02 jvs Renamed to ClickRepeater
15188 * 2007-02-03 jvs Modifications for FF Mac and Safari
15191 * @param {String/HTMLElement/Element} el The element to listen on
15192 * @param {Object} config
15194 Roo.util.ClickRepeater = function(el, config)
15196 this.el = Roo.get(el);
15197 this.el.unselectable();
15199 Roo.apply(this, config);
15204 * Fires when the mouse button is depressed.
15205 * @param {Roo.util.ClickRepeater} this
15207 "mousedown" : true,
15210 * Fires on a specified interval during the time the element is pressed.
15211 * @param {Roo.util.ClickRepeater} this
15216 * Fires when the mouse key is released.
15217 * @param {Roo.util.ClickRepeater} this
15222 this.el.on("mousedown", this.handleMouseDown, this);
15223 if(this.preventDefault || this.stopDefault){
15224 this.el.on("click", function(e){
15225 if(this.preventDefault){
15226 e.preventDefault();
15228 if(this.stopDefault){
15234 // allow inline handler
15236 this.on("click", this.handler, this.scope || this);
15239 Roo.util.ClickRepeater.superclass.constructor.call(this);
15242 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15245 preventDefault : true,
15246 stopDefault : false,
15250 handleMouseDown : function(){
15251 clearTimeout(this.timer);
15253 if(this.pressClass){
15254 this.el.addClass(this.pressClass);
15256 this.mousedownTime = new Date();
15258 Roo.get(document).on("mouseup", this.handleMouseUp, this);
15259 this.el.on("mouseout", this.handleMouseOut, this);
15261 this.fireEvent("mousedown", this);
15262 this.fireEvent("click", this);
15264 this.timer = this.click.defer(this.delay || this.interval, this);
15268 click : function(){
15269 this.fireEvent("click", this);
15270 this.timer = this.click.defer(this.getInterval(), this);
15274 getInterval: function(){
15275 if(!this.accelerate){
15276 return this.interval;
15278 var pressTime = this.mousedownTime.getElapsed();
15279 if(pressTime < 500){
15281 }else if(pressTime < 1700){
15283 }else if(pressTime < 2600){
15285 }else if(pressTime < 3500){
15287 }else if(pressTime < 4400){
15289 }else if(pressTime < 5300){
15291 }else if(pressTime < 6200){
15299 handleMouseOut : function(){
15300 clearTimeout(this.timer);
15301 if(this.pressClass){
15302 this.el.removeClass(this.pressClass);
15304 this.el.on("mouseover", this.handleMouseReturn, this);
15308 handleMouseReturn : function(){
15309 this.el.un("mouseover", this.handleMouseReturn);
15310 if(this.pressClass){
15311 this.el.addClass(this.pressClass);
15317 handleMouseUp : function(){
15318 clearTimeout(this.timer);
15319 this.el.un("mouseover", this.handleMouseReturn);
15320 this.el.un("mouseout", this.handleMouseOut);
15321 Roo.get(document).un("mouseup", this.handleMouseUp);
15322 this.el.removeClass(this.pressClass);
15323 this.fireEvent("mouseup", this);
15326 * @class Roo.util.Clipboard
15332 Roo.util.Clipboard = {
15334 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15335 * @param {String} text to copy to clipboard
15337 write : function(text) {
15338 // navigator clipboard api needs a secure context (https)
15339 if (navigator.clipboard && window.isSecureContext) {
15340 // navigator clipboard api method'
15341 navigator.clipboard.writeText(text);
15344 // text area method
15345 var ta = document.createElement("textarea");
15347 // make the textarea out of viewport
15348 ta.style.position = "fixed";
15349 ta.style.left = "-999999px";
15350 ta.style.top = "-999999px";
15351 document.body.appendChild(ta);
15354 document.execCommand('copy');
15364 * Ext JS Library 1.1.1
15365 * Copyright(c) 2006-2007, Ext JS, LLC.
15367 * Originally Released Under LGPL - original licence link has changed is not relivant.
15370 * <script type="text/javascript">
15375 * @class Roo.KeyNav
15376 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
15377 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15378 * way to implement custom navigation schemes for any UI component.</p>
15379 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15380 * pageUp, pageDown, del, home, end. Usage:</p>
15382 var nav = new Roo.KeyNav("my-element", {
15383 "left" : function(e){
15384 this.moveLeft(e.ctrlKey);
15386 "right" : function(e){
15387 this.moveRight(e.ctrlKey);
15389 "enter" : function(e){
15396 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15397 * @param {Object} config The config
15399 Roo.KeyNav = function(el, config){
15400 this.el = Roo.get(el);
15401 Roo.apply(this, config);
15402 if(!this.disabled){
15403 this.disabled = true;
15408 Roo.KeyNav.prototype = {
15410 * @cfg {Boolean} disabled
15411 * True to disable this KeyNav instance (defaults to false)
15415 * @cfg {String} defaultEventAction
15416 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
15417 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15418 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15420 defaultEventAction: "stopEvent",
15422 * @cfg {Boolean} forceKeyDown
15423 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
15424 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15425 * handle keydown instead of keypress.
15427 forceKeyDown : false,
15430 prepareEvent : function(e){
15431 var k = e.getKey();
15432 var h = this.keyToHandler[k];
15433 //if(h && this[h]){
15434 // e.stopPropagation();
15436 if(Roo.isSafari && h && k >= 37 && k <= 40){
15442 relay : function(e){
15443 var k = e.getKey();
15444 var h = this.keyToHandler[k];
15446 if(this.doRelay(e, this[h], h) !== true){
15447 e[this.defaultEventAction]();
15453 doRelay : function(e, h, hname){
15454 return h.call(this.scope || this, e);
15457 // possible handlers
15471 // quick lookup hash
15488 * Enable this KeyNav
15490 enable: function(){
15492 // ie won't do special keys on keypress, no one else will repeat keys with keydown
15493 // the EventObject will normalize Safari automatically
15494 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15495 this.el.on("keydown", this.relay, this);
15497 this.el.on("keydown", this.prepareEvent, this);
15498 this.el.on("keypress", this.relay, this);
15500 this.disabled = false;
15505 * Disable this KeyNav
15507 disable: function(){
15508 if(!this.disabled){
15509 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15510 this.el.un("keydown", this.relay);
15512 this.el.un("keydown", this.prepareEvent);
15513 this.el.un("keypress", this.relay);
15515 this.disabled = true;
15520 * Ext JS Library 1.1.1
15521 * Copyright(c) 2006-2007, Ext JS, LLC.
15523 * Originally Released Under LGPL - original licence link has changed is not relivant.
15526 * <script type="text/javascript">
15531 * @class Roo.KeyMap
15532 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15533 * The constructor accepts the same config object as defined by {@link #addBinding}.
15534 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15535 * combination it will call the function with this signature (if the match is a multi-key
15536 * combination the callback will still be called only once): (String key, Roo.EventObject e)
15537 * A KeyMap can also handle a string representation of keys.<br />
15540 // map one key by key code
15541 var map = new Roo.KeyMap("my-element", {
15542 key: 13, // or Roo.EventObject.ENTER
15547 // map multiple keys to one action by string
15548 var map = new Roo.KeyMap("my-element", {
15554 // map multiple keys to multiple actions by strings and array of codes
15555 var map = new Roo.KeyMap("my-element", [
15558 fn: function(){ alert("Return was pressed"); }
15561 fn: function(){ alert('a, b or c was pressed'); }
15566 fn: function(){ alert('Control + shift + tab was pressed.'); }
15570 * <b>Note: A KeyMap starts enabled</b>
15572 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15573 * @param {Object} config The config (see {@link #addBinding})
15574 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15576 Roo.KeyMap = function(el, config, eventName){
15577 this.el = Roo.get(el);
15578 this.eventName = eventName || "keydown";
15579 this.bindings = [];
15581 this.addBinding(config);
15586 Roo.KeyMap.prototype = {
15588 * True to stop the event from bubbling and prevent the default browser action if the
15589 * key was handled by the KeyMap (defaults to false)
15595 * Add a new binding to this KeyMap. The following config object properties are supported:
15597 Property Type Description
15598 ---------- --------------- ----------------------------------------------------------------------
15599 key String/Array A single keycode or an array of keycodes to handle
15600 shift Boolean True to handle key only when shift is pressed (defaults to false)
15601 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
15602 alt Boolean True to handle key only when alt is pressed (defaults to false)
15603 fn Function The function to call when KeyMap finds the expected key combination
15604 scope Object The scope of the callback function
15610 var map = new Roo.KeyMap(document, {
15611 key: Roo.EventObject.ENTER,
15616 //Add a new binding to the existing KeyMap later
15624 * @param {Object/Array} config A single KeyMap config or an array of configs
15626 addBinding : function(config){
15627 if(config instanceof Array){
15628 for(var i = 0, len = config.length; i < len; i++){
15629 this.addBinding(config[i]);
15633 var keyCode = config.key,
15634 shift = config.shift,
15635 ctrl = config.ctrl,
15638 scope = config.scope;
15639 if(typeof keyCode == "string"){
15641 var keyString = keyCode.toUpperCase();
15642 for(var j = 0, len = keyString.length; j < len; j++){
15643 ks.push(keyString.charCodeAt(j));
15647 var keyArray = keyCode instanceof Array;
15648 var handler = function(e){
15649 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
15650 var k = e.getKey();
15652 for(var i = 0, len = keyCode.length; i < len; i++){
15653 if(keyCode[i] == k){
15654 if(this.stopEvent){
15657 fn.call(scope || window, k, e);
15663 if(this.stopEvent){
15666 fn.call(scope || window, k, e);
15671 this.bindings.push(handler);
15675 * Shorthand for adding a single key listener
15676 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
15677 * following options:
15678 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
15679 * @param {Function} fn The function to call
15680 * @param {Object} scope (optional) The scope of the function
15682 on : function(key, fn, scope){
15683 var keyCode, shift, ctrl, alt;
15684 if(typeof key == "object" && !(key instanceof Array)){
15703 handleKeyDown : function(e){
15704 if(this.enabled){ //just in case
15705 var b = this.bindings;
15706 for(var i = 0, len = b.length; i < len; i++){
15707 b[i].call(this, e);
15713 * Returns true if this KeyMap is enabled
15714 * @return {Boolean}
15716 isEnabled : function(){
15717 return this.enabled;
15721 * Enables this KeyMap
15723 enable: function(){
15725 this.el.on(this.eventName, this.handleKeyDown, this);
15726 this.enabled = true;
15731 * Disable this KeyMap
15733 disable: function(){
15735 this.el.removeListener(this.eventName, this.handleKeyDown, this);
15736 this.enabled = false;
15741 * Ext JS Library 1.1.1
15742 * Copyright(c) 2006-2007, Ext JS, LLC.
15744 * Originally Released Under LGPL - original licence link has changed is not relivant.
15747 * <script type="text/javascript">
15752 * @class Roo.util.TextMetrics
15753 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15754 * wide, in pixels, a given block of text will be.
15757 Roo.util.TextMetrics = function(){
15761 * Measures the size of the specified text
15762 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15763 * that can affect the size of the rendered text
15764 * @param {String} text The text to measure
15765 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15766 * in order to accurately measure the text height
15767 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15769 measure : function(el, text, fixedWidth){
15771 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15774 shared.setFixedWidth(fixedWidth || 'auto');
15775 return shared.getSize(text);
15779 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
15780 * the overhead of multiple calls to initialize the style properties on each measurement.
15781 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15782 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15783 * in order to accurately measure the text height
15784 * @return {Roo.util.TextMetrics.Instance} instance The new instance
15786 createInstance : function(el, fixedWidth){
15787 return Roo.util.TextMetrics.Instance(el, fixedWidth);
15793 * @class Roo.util.TextMetrics.Instance
15794 * Instance of TextMetrics Calcuation
15796 * Create a new TextMetrics Instance
15797 * @param {Object} bindto
15798 * @param {Boolean} fixedWidth
15801 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
15803 var ml = new Roo.Element(document.createElement('div'));
15804 document.body.appendChild(ml.dom);
15805 ml.position('absolute');
15806 ml.setLeftTop(-1000, -1000);
15810 ml.setWidth(fixedWidth);
15815 * Returns the size of the specified text based on the internal element's style and width properties
15816 * @param {String} text The text to measure
15817 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15819 getSize : function(text){
15821 var s = ml.getSize();
15827 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15828 * that can affect the size of the rendered text
15829 * @param {String/HTMLElement} el The element, dom node or id
15831 bind : function(el){
15833 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15838 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15839 * to set a fixed width in order to accurately measure the text height.
15840 * @param {Number} width The width to set on the element
15842 setFixedWidth : function(width){
15843 ml.setWidth(width);
15847 * Returns the measured width of the specified text
15848 * @param {String} text The text to measure
15849 * @return {Number} width The width in pixels
15851 getWidth : function(text){
15852 ml.dom.style.width = 'auto';
15853 return this.getSize(text).width;
15857 * Returns the measured height of the specified text. For multiline text, be sure to call
15858 * {@link #setFixedWidth} if necessary.
15859 * @param {String} text The text to measure
15860 * @return {Number} height The height in pixels
15862 getHeight : function(text){
15863 return this.getSize(text).height;
15867 instance.bind(bindTo);
15872 // backwards compat
15873 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15875 * Ext JS Library 1.1.1
15876 * Copyright(c) 2006-2007, Ext JS, LLC.
15878 * Originally Released Under LGPL - original licence link has changed is not relivant.
15881 * <script type="text/javascript">
15885 * @class Roo.state.Provider
15886 * Abstract base class for state provider implementations. This class provides methods
15887 * for encoding and decoding <b>typed</b> variables including dates and defines the
15888 * Provider interface.
15890 Roo.state.Provider = function(){
15892 * @event statechange
15893 * Fires when a state change occurs.
15894 * @param {Provider} this This state provider
15895 * @param {String} key The state key which was changed
15896 * @param {String} value The encoded value for the state
15899 "statechange": true
15902 Roo.state.Provider.superclass.constructor.call(this);
15904 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15906 * Returns the current value for a key
15907 * @param {String} name The key name
15908 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15909 * @return {Mixed} The state data
15911 get : function(name, defaultValue){
15912 return typeof this.state[name] == "undefined" ?
15913 defaultValue : this.state[name];
15917 * Clears a value from the state
15918 * @param {String} name The key name
15920 clear : function(name){
15921 delete this.state[name];
15922 this.fireEvent("statechange", this, name, null);
15926 * Sets the value for a key
15927 * @param {String} name The key name
15928 * @param {Mixed} value The value to set
15930 set : function(name, value){
15931 this.state[name] = value;
15932 this.fireEvent("statechange", this, name, value);
15936 * Decodes a string previously encoded with {@link #encodeValue}.
15937 * @param {String} value The value to decode
15938 * @return {Mixed} The decoded value
15940 decodeValue : function(cookie){
15941 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15942 var matches = re.exec(unescape(cookie));
15943 if(!matches || !matches[1]) {
15944 return; // non state cookie
15946 var type = matches[1];
15947 var v = matches[2];
15950 return parseFloat(v);
15952 return new Date(Date.parse(v));
15957 var values = v.split("^");
15958 for(var i = 0, len = values.length; i < len; i++){
15959 all.push(this.decodeValue(values[i]));
15964 var values = v.split("^");
15965 for(var i = 0, len = values.length; i < len; i++){
15966 var kv = values[i].split("=");
15967 all[kv[0]] = this.decodeValue(kv[1]);
15976 * Encodes a value including type information. Decode with {@link #decodeValue}.
15977 * @param {Mixed} value The value to encode
15978 * @return {String} The encoded value
15980 encodeValue : function(v){
15982 if(typeof v == "number"){
15984 }else if(typeof v == "boolean"){
15985 enc = "b:" + (v ? "1" : "0");
15986 }else if(v instanceof Date){
15987 enc = "d:" + v.toGMTString();
15988 }else if(v instanceof Array){
15990 for(var i = 0, len = v.length; i < len; i++){
15991 flat += this.encodeValue(v[i]);
15997 }else if(typeof v == "object"){
16000 if(typeof v[key] != "function"){
16001 flat += key + "=" + this.encodeValue(v[key]) + "^";
16004 enc = "o:" + flat.substring(0, flat.length-1);
16008 return escape(enc);
16014 * Ext JS Library 1.1.1
16015 * Copyright(c) 2006-2007, Ext JS, LLC.
16017 * Originally Released Under LGPL - original licence link has changed is not relivant.
16020 * <script type="text/javascript">
16023 * @class Roo.state.Manager
16024 * This is the global state manager. By default all components that are "state aware" check this class
16025 * for state information if you don't pass them a custom state provider. In order for this class
16026 * to be useful, it must be initialized with a provider when your application initializes.
16028 // in your initialization function
16030 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16032 // supposed you have a {@link Roo.BorderLayout}
16033 var layout = new Roo.BorderLayout(...);
16034 layout.restoreState();
16035 // or a {Roo.BasicDialog}
16036 var dialog = new Roo.BasicDialog(...);
16037 dialog.restoreState();
16041 Roo.state.Manager = function(){
16042 var provider = new Roo.state.Provider();
16046 * Configures the default state provider for your application
16047 * @param {Provider} stateProvider The state provider to set
16049 setProvider : function(stateProvider){
16050 provider = stateProvider;
16054 * Returns the current value for a key
16055 * @param {String} name The key name
16056 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16057 * @return {Mixed} The state data
16059 get : function(key, defaultValue){
16060 return provider.get(key, defaultValue);
16064 * Sets the value for a key
16065 * @param {String} name The key name
16066 * @param {Mixed} value The state data
16068 set : function(key, value){
16069 provider.set(key, value);
16073 * Clears a value from the state
16074 * @param {String} name The key name
16076 clear : function(key){
16077 provider.clear(key);
16081 * Gets the currently configured state provider
16082 * @return {Provider} The state provider
16084 getProvider : function(){
16091 * Ext JS Library 1.1.1
16092 * Copyright(c) 2006-2007, Ext JS, LLC.
16094 * Originally Released Under LGPL - original licence link has changed is not relivant.
16097 * <script type="text/javascript">
16100 * @class Roo.state.CookieProvider
16101 * @extends Roo.state.Provider
16102 * The default Provider implementation which saves state via cookies.
16105 var cp = new Roo.state.CookieProvider({
16107 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16108 domain: "roojs.com"
16110 Roo.state.Manager.setProvider(cp);
16112 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16113 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16114 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
16115 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16116 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16117 * domain the page is running on including the 'www' like 'www.roojs.com')
16118 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16120 * Create a new CookieProvider
16121 * @param {Object} config The configuration object
16123 Roo.state.CookieProvider = function(config){
16124 Roo.state.CookieProvider.superclass.constructor.call(this);
16126 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16127 this.domain = null;
16128 this.secure = false;
16129 Roo.apply(this, config);
16130 this.state = this.readCookies();
16133 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16135 set : function(name, value){
16136 if(typeof value == "undefined" || value === null){
16140 this.setCookie(name, value);
16141 Roo.state.CookieProvider.superclass.set.call(this, name, value);
16145 clear : function(name){
16146 this.clearCookie(name);
16147 Roo.state.CookieProvider.superclass.clear.call(this, name);
16151 readCookies : function(){
16153 var c = document.cookie + ";";
16154 var re = /\s?(.*?)=(.*?);/g;
16156 while((matches = re.exec(c)) != null){
16157 var name = matches[1];
16158 var value = matches[2];
16159 if(name && name.substring(0,3) == "ys-"){
16160 cookies[name.substr(3)] = this.decodeValue(value);
16167 setCookie : function(name, value){
16168 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16169 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16170 ((this.path == null) ? "" : ("; path=" + this.path)) +
16171 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16172 ((this.secure == true) ? "; secure" : "");
16176 clearCookie : function(name){
16177 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16178 ((this.path == null) ? "" : ("; path=" + this.path)) +
16179 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16180 ((this.secure == true) ? "; secure" : "");
16184 * Ext JS Library 1.1.1
16185 * Copyright(c) 2006-2007, Ext JS, LLC.
16187 * Originally Released Under LGPL - original licence link has changed is not relivant.
16190 * <script type="text/javascript">
16195 * @class Roo.ComponentMgr
16196 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16199 Roo.ComponentMgr = function(){
16200 var all = new Roo.util.MixedCollection();
16204 * Registers a component.
16205 * @param {Roo.Component} c The component
16207 register : function(c){
16212 * Unregisters a component.
16213 * @param {Roo.Component} c The component
16215 unregister : function(c){
16220 * Returns a component by id
16221 * @param {String} id The component id
16223 get : function(id){
16224 return all.get(id);
16228 * Registers a function that will be called when a specified component is added to ComponentMgr
16229 * @param {String} id The component id
16230 * @param {Funtction} fn The callback function
16231 * @param {Object} scope The scope of the callback
16233 onAvailable : function(id, fn, scope){
16234 all.on("add", function(index, o){
16236 fn.call(scope || o, o);
16237 all.un("add", fn, scope);
16244 * Ext JS Library 1.1.1
16245 * Copyright(c) 2006-2007, Ext JS, LLC.
16247 * Originally Released Under LGPL - original licence link has changed is not relivant.
16250 * <script type="text/javascript">
16254 * @class Roo.Component
16255 * @extends Roo.util.Observable
16256 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
16257 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
16258 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16259 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16260 * All visual components (widgets) that require rendering into a layout should subclass Component.
16262 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
16263 * 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
16264 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
16266 Roo.Component = function(config){
16267 config = config || {};
16268 if(config.tagName || config.dom || typeof config == "string"){ // element object
16269 config = {el: config, id: config.id || config};
16271 this.initialConfig = config;
16273 Roo.apply(this, config);
16277 * Fires after the component is disabled.
16278 * @param {Roo.Component} this
16283 * Fires after the component is enabled.
16284 * @param {Roo.Component} this
16288 * @event beforeshow
16289 * Fires before the component is shown. Return false to stop the show.
16290 * @param {Roo.Component} this
16295 * Fires after the component is shown.
16296 * @param {Roo.Component} this
16300 * @event beforehide
16301 * Fires before the component is hidden. Return false to stop the hide.
16302 * @param {Roo.Component} this
16307 * Fires after the component is hidden.
16308 * @param {Roo.Component} this
16312 * @event beforerender
16313 * Fires before the component is rendered. Return false to stop the render.
16314 * @param {Roo.Component} this
16316 beforerender : true,
16319 * Fires after the component is rendered.
16320 * @param {Roo.Component} this
16324 * @event beforedestroy
16325 * Fires before the component is destroyed. Return false to stop the destroy.
16326 * @param {Roo.Component} this
16328 beforedestroy : true,
16331 * Fires after the component is destroyed.
16332 * @param {Roo.Component} this
16337 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16339 Roo.ComponentMgr.register(this);
16340 Roo.Component.superclass.constructor.call(this);
16341 this.initComponent();
16342 if(this.renderTo){ // not supported by all components yet. use at your own risk!
16343 this.render(this.renderTo);
16344 delete this.renderTo;
16349 Roo.Component.AUTO_ID = 1000;
16351 Roo.extend(Roo.Component, Roo.util.Observable, {
16353 * @scope Roo.Component.prototype
16355 * true if this component is hidden. Read-only.
16360 * true if this component is disabled. Read-only.
16365 * true if this component has been rendered. Read-only.
16369 /** @cfg {String} disableClass
16370 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16372 disabledClass : "x-item-disabled",
16373 /** @cfg {Boolean} allowDomMove
16374 * Whether the component can move the Dom node when rendering (defaults to true).
16376 allowDomMove : true,
16377 /** @cfg {String} hideMode (display|visibility)
16378 * How this component should hidden. Supported values are
16379 * "visibility" (css visibility), "offsets" (negative offset position) and
16380 * "display" (css display) - defaults to "display".
16382 hideMode: 'display',
16385 ctype : "Roo.Component",
16388 * @cfg {String} actionMode
16389 * which property holds the element that used for hide() / show() / disable() / enable()
16390 * default is 'el' for forms you probably want to set this to fieldEl
16395 getActionEl : function(){
16396 return this[this.actionMode];
16399 initComponent : Roo.emptyFn,
16401 * If this is a lazy rendering component, render it to its container element.
16402 * @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.
16404 render : function(container, position){
16410 if(this.fireEvent("beforerender", this) === false){
16414 if(!container && this.el){
16415 this.el = Roo.get(this.el);
16416 container = this.el.dom.parentNode;
16417 this.allowDomMove = false;
16419 this.container = Roo.get(container);
16420 this.rendered = true;
16421 if(position !== undefined){
16422 if(typeof position == 'number'){
16423 position = this.container.dom.childNodes[position];
16425 position = Roo.getDom(position);
16428 this.onRender(this.container, position || null);
16430 this.el.addClass(this.cls);
16434 this.el.applyStyles(this.style);
16437 this.fireEvent("render", this);
16438 this.afterRender(this.container);
16451 // default function is not really useful
16452 onRender : function(ct, position){
16454 this.el = Roo.get(this.el);
16455 if(this.allowDomMove !== false){
16456 ct.dom.insertBefore(this.el.dom, position);
16462 getAutoCreate : function(){
16463 var cfg = typeof this.autoCreate == "object" ?
16464 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16465 if(this.id && !cfg.id){
16472 afterRender : Roo.emptyFn,
16475 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16476 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16478 destroy : function(){
16479 if(this.fireEvent("beforedestroy", this) !== false){
16480 this.purgeListeners();
16481 this.beforeDestroy();
16483 this.el.removeAllListeners();
16485 if(this.actionMode == "container"){
16486 this.container.remove();
16490 Roo.ComponentMgr.unregister(this);
16491 this.fireEvent("destroy", this);
16496 beforeDestroy : function(){
16501 onDestroy : function(){
16506 * Returns the underlying {@link Roo.Element}.
16507 * @return {Roo.Element} The element
16509 getEl : function(){
16514 * Returns the id of this component.
16517 getId : function(){
16522 * Try to focus this component.
16523 * @param {Boolean} selectText True to also select the text in this component (if applicable)
16524 * @return {Roo.Component} this
16526 focus : function(selectText){
16529 if(selectText === true){
16530 this.el.dom.select();
16545 * Disable this component.
16546 * @return {Roo.Component} this
16548 disable : function(){
16552 this.disabled = true;
16553 this.fireEvent("disable", this);
16558 onDisable : function(){
16559 this.getActionEl().addClass(this.disabledClass);
16560 this.el.dom.disabled = true;
16564 * Enable this component.
16565 * @return {Roo.Component} this
16567 enable : function(){
16571 this.disabled = false;
16572 this.fireEvent("enable", this);
16577 onEnable : function(){
16578 this.getActionEl().removeClass(this.disabledClass);
16579 this.el.dom.disabled = false;
16583 * Convenience function for setting disabled/enabled by boolean.
16584 * @param {Boolean} disabled
16586 setDisabled : function(disabled){
16587 this[disabled ? "disable" : "enable"]();
16591 * Show this component.
16592 * @return {Roo.Component} this
16595 if(this.fireEvent("beforeshow", this) !== false){
16596 this.hidden = false;
16600 this.fireEvent("show", this);
16606 onShow : function(){
16607 var ae = this.getActionEl();
16608 if(this.hideMode == 'visibility'){
16609 ae.dom.style.visibility = "visible";
16610 }else if(this.hideMode == 'offsets'){
16611 ae.removeClass('x-hidden');
16613 ae.dom.style.display = "";
16618 * Hide this component.
16619 * @return {Roo.Component} this
16622 if(this.fireEvent("beforehide", this) !== false){
16623 this.hidden = true;
16627 this.fireEvent("hide", this);
16633 onHide : function(){
16634 var ae = this.getActionEl();
16635 if(this.hideMode == 'visibility'){
16636 ae.dom.style.visibility = "hidden";
16637 }else if(this.hideMode == 'offsets'){
16638 ae.addClass('x-hidden');
16640 ae.dom.style.display = "none";
16645 * Convenience function to hide or show this component by boolean.
16646 * @param {Boolean} visible True to show, false to hide
16647 * @return {Roo.Component} this
16649 setVisible: function(visible){
16659 * Returns true if this component is visible.
16661 isVisible : function(){
16662 return this.getActionEl().isVisible();
16665 cloneConfig : function(overrides){
16666 overrides = overrides || {};
16667 var id = overrides.id || Roo.id();
16668 var cfg = Roo.applyIf(overrides, this.initialConfig);
16669 cfg.id = id; // prevent dup id
16670 return new this.constructor(cfg);
16674 * Ext JS Library 1.1.1
16675 * Copyright(c) 2006-2007, Ext JS, LLC.
16677 * Originally Released Under LGPL - original licence link has changed is not relivant.
16680 * <script type="text/javascript">
16684 * @class Roo.BoxComponent
16685 * @extends Roo.Component
16686 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
16687 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
16688 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
16689 * layout containers.
16691 * @param {Roo.Element/String/Object} config The configuration options.
16693 Roo.BoxComponent = function(config){
16694 Roo.Component.call(this, config);
16698 * Fires after the component is resized.
16699 * @param {Roo.Component} this
16700 * @param {Number} adjWidth The box-adjusted width that was set
16701 * @param {Number} adjHeight The box-adjusted height that was set
16702 * @param {Number} rawWidth The width that was originally specified
16703 * @param {Number} rawHeight The height that was originally specified
16708 * Fires after the component is moved.
16709 * @param {Roo.Component} this
16710 * @param {Number} x The new x position
16711 * @param {Number} y The new y position
16717 Roo.extend(Roo.BoxComponent, Roo.Component, {
16718 // private, set in afterRender to signify that the component has been rendered
16720 // private, used to defer height settings to subclasses
16721 deferHeight: false,
16722 /** @cfg {Number} width
16723 * width (optional) size of component
16725 /** @cfg {Number} height
16726 * height (optional) size of component
16730 * Sets the width and height of the component. This method fires the resize event. This method can accept
16731 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16732 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16733 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16734 * @return {Roo.BoxComponent} this
16736 setSize : function(w, h){
16737 // support for standard size objects
16738 if(typeof w == 'object'){
16743 if(!this.boxReady){
16749 // prevent recalcs when not needed
16750 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16753 this.lastSize = {width: w, height: h};
16755 var adj = this.adjustSize(w, h);
16756 var aw = adj.width, ah = adj.height;
16757 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16758 var rz = this.getResizeEl();
16759 if(!this.deferHeight && aw !== undefined && ah !== undefined){
16760 rz.setSize(aw, ah);
16761 }else if(!this.deferHeight && ah !== undefined){
16763 }else if(aw !== undefined){
16766 this.onResize(aw, ah, w, h);
16767 this.fireEvent('resize', this, aw, ah, w, h);
16773 * Gets the current size of the component's underlying element.
16774 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16776 getSize : function(){
16777 return this.el.getSize();
16781 * Gets the current XY position of the component's underlying element.
16782 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16783 * @return {Array} The XY position of the element (e.g., [100, 200])
16785 getPosition : function(local){
16786 if(local === true){
16787 return [this.el.getLeft(true), this.el.getTop(true)];
16789 return this.xy || this.el.getXY();
16793 * Gets the current box measurements of the component's underlying element.
16794 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16795 * @returns {Object} box An object in the format {x, y, width, height}
16797 getBox : function(local){
16798 var s = this.el.getSize();
16800 s.x = this.el.getLeft(true);
16801 s.y = this.el.getTop(true);
16803 var xy = this.xy || this.el.getXY();
16811 * Sets the current box measurements of the component's underlying element.
16812 * @param {Object} box An object in the format {x, y, width, height}
16813 * @returns {Roo.BoxComponent} this
16815 updateBox : function(box){
16816 this.setSize(box.width, box.height);
16817 this.setPagePosition(box.x, box.y);
16822 getResizeEl : function(){
16823 return this.resizeEl || this.el;
16827 getPositionEl : function(){
16828 return this.positionEl || this.el;
16832 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16833 * This method fires the move event.
16834 * @param {Number} left The new left
16835 * @param {Number} top The new top
16836 * @returns {Roo.BoxComponent} this
16838 setPosition : function(x, y){
16841 if(!this.boxReady){
16844 var adj = this.adjustPosition(x, y);
16845 var ax = adj.x, ay = adj.y;
16847 var el = this.getPositionEl();
16848 if(ax !== undefined || ay !== undefined){
16849 if(ax !== undefined && ay !== undefined){
16850 el.setLeftTop(ax, ay);
16851 }else if(ax !== undefined){
16853 }else if(ay !== undefined){
16856 this.onPosition(ax, ay);
16857 this.fireEvent('move', this, ax, ay);
16863 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16864 * This method fires the move event.
16865 * @param {Number} x The new x position
16866 * @param {Number} y The new y position
16867 * @returns {Roo.BoxComponent} this
16869 setPagePosition : function(x, y){
16872 if(!this.boxReady){
16875 if(x === undefined || y === undefined){ // cannot translate undefined points
16878 var p = this.el.translatePoints(x, y);
16879 this.setPosition(p.left, p.top);
16884 onRender : function(ct, position){
16885 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16887 this.resizeEl = Roo.get(this.resizeEl);
16889 if(this.positionEl){
16890 this.positionEl = Roo.get(this.positionEl);
16895 afterRender : function(){
16896 Roo.BoxComponent.superclass.afterRender.call(this);
16897 this.boxReady = true;
16898 this.setSize(this.width, this.height);
16899 if(this.x || this.y){
16900 this.setPosition(this.x, this.y);
16902 if(this.pageX || this.pageY){
16903 this.setPagePosition(this.pageX, this.pageY);
16908 * Force the component's size to recalculate based on the underlying element's current height and width.
16909 * @returns {Roo.BoxComponent} this
16911 syncSize : function(){
16912 delete this.lastSize;
16913 this.setSize(this.el.getWidth(), this.el.getHeight());
16918 * Called after the component is resized, this method is empty by default but can be implemented by any
16919 * subclass that needs to perform custom logic after a resize occurs.
16920 * @param {Number} adjWidth The box-adjusted width that was set
16921 * @param {Number} adjHeight The box-adjusted height that was set
16922 * @param {Number} rawWidth The width that was originally specified
16923 * @param {Number} rawHeight The height that was originally specified
16925 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16930 * Called after the component is moved, this method is empty by default but can be implemented by any
16931 * subclass that needs to perform custom logic after a move occurs.
16932 * @param {Number} x The new x position
16933 * @param {Number} y The new y position
16935 onPosition : function(x, y){
16940 adjustSize : function(w, h){
16941 if(this.autoWidth){
16944 if(this.autoHeight){
16947 return {width : w, height: h};
16951 adjustPosition : function(x, y){
16952 return {x : x, y: y};
16956 * Ext JS Library 1.1.1
16957 * Copyright(c) 2006-2007, Ext JS, LLC.
16959 * Originally Released Under LGPL - original licence link has changed is not relivant.
16962 * <script type="text/javascript">
16967 * @extends Roo.Element
16968 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16969 * automatic maintaining of shadow/shim positions.
16970 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16971 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16972 * you can pass a string with a CSS class name. False turns off the shadow.
16973 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16974 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16975 * @cfg {String} cls CSS class to add to the element
16976 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16977 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16979 * @param {Object} config An object with config options.
16980 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16983 Roo.Layer = function(config, existingEl){
16984 config = config || {};
16985 var dh = Roo.DomHelper;
16986 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16988 this.dom = Roo.getDom(existingEl);
16991 var o = config.dh || {tag: "div", cls: "x-layer"};
16992 this.dom = dh.append(pel, o);
16995 this.addClass(config.cls);
16997 this.constrain = config.constrain !== false;
16998 this.visibilityMode = Roo.Element.VISIBILITY;
17000 this.id = this.dom.id = config.id;
17002 this.id = Roo.id(this.dom);
17004 this.zindex = config.zindex || this.getZIndex();
17005 this.position("absolute", this.zindex);
17007 this.shadowOffset = config.shadowOffset || 4;
17008 this.shadow = new Roo.Shadow({
17009 offset : this.shadowOffset,
17010 mode : config.shadow
17013 this.shadowOffset = 0;
17015 this.useShim = config.shim !== false && Roo.useShims;
17016 this.useDisplay = config.useDisplay;
17020 var supr = Roo.Element.prototype;
17022 // shims are shared among layer to keep from having 100 iframes
17025 Roo.extend(Roo.Layer, Roo.Element, {
17027 getZIndex : function(){
17028 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17031 getShim : function(){
17038 var shim = shims.shift();
17040 shim = this.createShim();
17041 shim.enableDisplayMode('block');
17042 shim.dom.style.display = 'none';
17043 shim.dom.style.visibility = 'visible';
17045 var pn = this.dom.parentNode;
17046 if(shim.dom.parentNode != pn){
17047 pn.insertBefore(shim.dom, this.dom);
17049 shim.setStyle('z-index', this.getZIndex()-2);
17054 hideShim : function(){
17056 this.shim.setDisplayed(false);
17057 shims.push(this.shim);
17062 disableShadow : function(){
17064 this.shadowDisabled = true;
17065 this.shadow.hide();
17066 this.lastShadowOffset = this.shadowOffset;
17067 this.shadowOffset = 0;
17071 enableShadow : function(show){
17073 this.shadowDisabled = false;
17074 this.shadowOffset = this.lastShadowOffset;
17075 delete this.lastShadowOffset;
17083 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17084 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17085 sync : function(doShow){
17086 var sw = this.shadow;
17087 if(!this.updating && this.isVisible() && (sw || this.useShim)){
17088 var sh = this.getShim();
17090 var w = this.getWidth(),
17091 h = this.getHeight();
17093 var l = this.getLeft(true),
17094 t = this.getTop(true);
17096 if(sw && !this.shadowDisabled){
17097 if(doShow && !sw.isVisible()){
17100 sw.realign(l, t, w, h);
17106 // fit the shim behind the shadow, so it is shimmed too
17107 var a = sw.adjusts, s = sh.dom.style;
17108 s.left = (Math.min(l, l+a.l))+"px";
17109 s.top = (Math.min(t, t+a.t))+"px";
17110 s.width = (w+a.w)+"px";
17111 s.height = (h+a.h)+"px";
17118 sh.setLeftTop(l, t);
17125 destroy : function(){
17128 this.shadow.hide();
17130 this.removeAllListeners();
17131 var pn = this.dom.parentNode;
17133 pn.removeChild(this.dom);
17135 Roo.Element.uncache(this.id);
17138 remove : function(){
17143 beginUpdate : function(){
17144 this.updating = true;
17148 endUpdate : function(){
17149 this.updating = false;
17154 hideUnders : function(negOffset){
17156 this.shadow.hide();
17162 constrainXY : function(){
17163 if(this.constrain){
17164 var vw = Roo.lib.Dom.getViewWidth(),
17165 vh = Roo.lib.Dom.getViewHeight();
17166 var s = Roo.get(document).getScroll();
17168 var xy = this.getXY();
17169 var x = xy[0], y = xy[1];
17170 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17171 // only move it if it needs it
17173 // first validate right/bottom
17174 if((x + w) > vw+s.left){
17175 x = vw - w - this.shadowOffset;
17178 if((y + h) > vh+s.top){
17179 y = vh - h - this.shadowOffset;
17182 // then make sure top/left isn't negative
17193 var ay = this.avoidY;
17194 if(y <= ay && (y+h) >= ay){
17200 supr.setXY.call(this, xy);
17206 isVisible : function(){
17207 return this.visible;
17211 showAction : function(){
17212 this.visible = true; // track visibility to prevent getStyle calls
17213 if(this.useDisplay === true){
17214 this.setDisplayed("");
17215 }else if(this.lastXY){
17216 supr.setXY.call(this, this.lastXY);
17217 }else if(this.lastLT){
17218 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17223 hideAction : function(){
17224 this.visible = false;
17225 if(this.useDisplay === true){
17226 this.setDisplayed(false);
17228 this.setLeftTop(-10000,-10000);
17232 // overridden Element method
17233 setVisible : function(v, a, d, c, e){
17238 var cb = function(){
17243 }.createDelegate(this);
17244 supr.setVisible.call(this, true, true, d, cb, e);
17247 this.hideUnders(true);
17256 }.createDelegate(this);
17258 supr.setVisible.call(this, v, a, d, cb, e);
17267 storeXY : function(xy){
17268 delete this.lastLT;
17272 storeLeftTop : function(left, top){
17273 delete this.lastXY;
17274 this.lastLT = [left, top];
17278 beforeFx : function(){
17279 this.beforeAction();
17280 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17284 afterFx : function(){
17285 Roo.Layer.superclass.afterFx.apply(this, arguments);
17286 this.sync(this.isVisible());
17290 beforeAction : function(){
17291 if(!this.updating && this.shadow){
17292 this.shadow.hide();
17296 // overridden Element method
17297 setLeft : function(left){
17298 this.storeLeftTop(left, this.getTop(true));
17299 supr.setLeft.apply(this, arguments);
17303 setTop : function(top){
17304 this.storeLeftTop(this.getLeft(true), top);
17305 supr.setTop.apply(this, arguments);
17309 setLeftTop : function(left, top){
17310 this.storeLeftTop(left, top);
17311 supr.setLeftTop.apply(this, arguments);
17315 setXY : function(xy, a, d, c, e){
17317 this.beforeAction();
17319 var cb = this.createCB(c);
17320 supr.setXY.call(this, xy, a, d, cb, e);
17327 createCB : function(c){
17338 // overridden Element method
17339 setX : function(x, a, d, c, e){
17340 this.setXY([x, this.getY()], a, d, c, e);
17343 // overridden Element method
17344 setY : function(y, a, d, c, e){
17345 this.setXY([this.getX(), y], a, d, c, e);
17348 // overridden Element method
17349 setSize : function(w, h, a, d, c, e){
17350 this.beforeAction();
17351 var cb = this.createCB(c);
17352 supr.setSize.call(this, w, h, a, d, cb, e);
17358 // overridden Element method
17359 setWidth : function(w, a, d, c, e){
17360 this.beforeAction();
17361 var cb = this.createCB(c);
17362 supr.setWidth.call(this, w, a, d, cb, e);
17368 // overridden Element method
17369 setHeight : function(h, a, d, c, e){
17370 this.beforeAction();
17371 var cb = this.createCB(c);
17372 supr.setHeight.call(this, h, a, d, cb, e);
17378 // overridden Element method
17379 setBounds : function(x, y, w, h, a, d, c, e){
17380 this.beforeAction();
17381 var cb = this.createCB(c);
17383 this.storeXY([x, y]);
17384 supr.setXY.call(this, [x, y]);
17385 supr.setSize.call(this, w, h, a, d, cb, e);
17388 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17394 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17395 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17396 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17397 * @param {Number} zindex The new z-index to set
17398 * @return {this} The Layer
17400 setZIndex : function(zindex){
17401 this.zindex = zindex;
17402 this.setStyle("z-index", zindex + 2);
17404 this.shadow.setZIndex(zindex + 1);
17407 this.shim.setStyle("z-index", zindex);
17412 * Original code for Roojs - LGPL
17413 * <script type="text/javascript">
17417 * @class Roo.XComponent
17418 * A delayed Element creator...
17419 * Or a way to group chunks of interface together.
17420 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17421 * used in conjunction with XComponent.build() it will create an instance of each element,
17422 * then call addxtype() to build the User interface.
17424 * Mypart.xyx = new Roo.XComponent({
17426 parent : 'Mypart.xyz', // empty == document.element.!!
17430 disabled : function() {}
17432 tree : function() { // return an tree of xtype declared components
17436 xtype : 'NestedLayoutPanel',
17443 * It can be used to build a big heiracy, with parent etc.
17444 * or you can just use this to render a single compoent to a dom element
17445 * MYPART.render(Roo.Element | String(id) | dom_element )
17452 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17453 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17455 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17457 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17458 * - if mulitple topModules exist, the last one is defined as the top module.
17462 * When the top level or multiple modules are to embedded into a existing HTML page,
17463 * the parent element can container '#id' of the element where the module will be drawn.
17467 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17468 * it relies more on a include mechanism, where sub modules are included into an outer page.
17469 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17471 * Bootstrap Roo Included elements
17473 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17474 * hence confusing the component builder as it thinks there are multiple top level elements.
17476 * String Over-ride & Translations
17478 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17479 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17480 * are needed. @see Roo.XComponent.overlayString
17484 * @extends Roo.util.Observable
17486 * @param cfg {Object} configuration of component
17489 Roo.XComponent = function(cfg) {
17490 Roo.apply(this, cfg);
17494 * Fires when this the componnt is built
17495 * @param {Roo.XComponent} c the component
17500 this.region = this.region || 'center'; // default..
17501 Roo.XComponent.register(this);
17502 this.modules = false;
17503 this.el = false; // where the layout goes..
17507 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17510 * The created element (with Roo.factory())
17511 * @type {Roo.Layout}
17517 * for BC - use el in new code
17518 * @type {Roo.Layout}
17524 * for BC - use el in new code
17525 * @type {Roo.Layout}
17530 * @cfg {Function|boolean} disabled
17531 * If this module is disabled by some rule, return true from the funtion
17536 * @cfg {String} parent
17537 * Name of parent element which it get xtype added to..
17542 * @cfg {String} order
17543 * Used to set the order in which elements are created (usefull for multiple tabs)
17548 * @cfg {String} name
17549 * String to display while loading.
17553 * @cfg {String} region
17554 * Region to render component to (defaults to center)
17559 * @cfg {Array} items
17560 * A single item array - the first element is the root of the tree..
17561 * It's done this way to stay compatible with the Xtype system...
17567 * The method that retuns the tree of parts that make up this compoennt
17574 * render element to dom or tree
17575 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17578 render : function(el)
17582 var hp = this.parent ? 1 : 0;
17583 Roo.debug && Roo.log(this);
17585 var tree = this._tree ? this._tree() : this.tree();
17588 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17589 // if parent is a '#.....' string, then let's use that..
17590 var ename = this.parent.substr(1);
17591 this.parent = false;
17592 Roo.debug && Roo.log(ename);
17594 case 'bootstrap-body':
17595 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
17596 // this is the BorderLayout standard?
17597 this.parent = { el : true };
17600 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
17601 // need to insert stuff...
17603 el : new Roo.bootstrap.layout.Border({
17604 el : document.body,
17610 tabPosition: 'top',
17611 //resizeTabs: true,
17612 alwaysShowTabs: true,
17622 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
17623 this.parent = { el : new Roo.bootstrap.Body() };
17624 Roo.debug && Roo.log("setting el to doc body");
17627 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
17631 this.parent = { el : true};
17634 el = Roo.get(ename);
17635 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
17636 this.parent = { el : true};
17643 if (!el && !this.parent) {
17644 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
17649 Roo.debug && Roo.log("EL:");
17650 Roo.debug && Roo.log(el);
17651 Roo.debug && Roo.log("this.parent.el:");
17652 Roo.debug && Roo.log(this.parent.el);
17655 // altertive root elements ??? - we need a better way to indicate these.
17656 var is_alt = Roo.XComponent.is_alt ||
17657 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
17658 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
17659 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
17663 if (!this.parent && is_alt) {
17664 //el = Roo.get(document.body);
17665 this.parent = { el : true };
17670 if (!this.parent) {
17672 Roo.debug && Roo.log("no parent - creating one");
17674 el = el ? Roo.get(el) : false;
17676 if (typeof(Roo.BorderLayout) == 'undefined' ) {
17679 el : new Roo.bootstrap.layout.Border({
17680 el: el || document.body,
17686 tabPosition: 'top',
17687 //resizeTabs: true,
17688 alwaysShowTabs: false,
17691 overflow: 'visible'
17697 // it's a top level one..
17699 el : new Roo.BorderLayout(el || document.body, {
17704 tabPosition: 'top',
17705 //resizeTabs: true,
17706 alwaysShowTabs: el && hp? false : true,
17707 hideTabs: el || !hp ? true : false,
17715 if (!this.parent.el) {
17716 // probably an old style ctor, which has been disabled.
17720 // The 'tree' method is '_tree now'
17722 tree.region = tree.region || this.region;
17723 var is_body = false;
17724 if (this.parent.el === true) {
17725 // bootstrap... - body..
17729 this.parent.el = Roo.factory(tree);
17733 this.el = this.parent.el.addxtype(tree, undefined, is_body);
17734 this.fireEvent('built', this);
17736 this.panel = this.el;
17737 this.layout = this.panel.layout;
17738 this.parentLayout = this.parent.layout || false;
17744 Roo.apply(Roo.XComponent, {
17746 * @property hideProgress
17747 * true to disable the building progress bar.. usefull on single page renders.
17750 hideProgress : false,
17752 * @property buildCompleted
17753 * True when the builder has completed building the interface.
17756 buildCompleted : false,
17759 * @property topModule
17760 * the upper most module - uses document.element as it's constructor.
17767 * @property modules
17768 * array of modules to be created by registration system.
17769 * @type {Array} of Roo.XComponent
17774 * @property elmodules
17775 * array of modules to be created by which use #ID
17776 * @type {Array} of Roo.XComponent
17783 * Is an alternative Root - normally used by bootstrap or other systems,
17784 * where the top element in the tree can wrap 'body'
17785 * @type {boolean} (default false)
17790 * @property build_from_html
17791 * Build elements from html - used by bootstrap HTML stuff
17792 * - this is cleared after build is completed
17793 * @type {boolean} (default false)
17796 build_from_html : false,
17798 * Register components to be built later.
17800 * This solves the following issues
17801 * - Building is not done on page load, but after an authentication process has occured.
17802 * - Interface elements are registered on page load
17803 * - Parent Interface elements may not be loaded before child, so this handles that..
17810 module : 'Pman.Tab.projectMgr',
17812 parent : 'Pman.layout',
17813 disabled : false, // or use a function..
17816 * * @param {Object} details about module
17818 register : function(obj) {
17820 Roo.XComponent.event.fireEvent('register', obj);
17821 switch(typeof(obj.disabled) ) {
17827 if ( obj.disabled() ) {
17833 if (obj.disabled || obj.region == '#disabled') {
17839 this.modules.push(obj);
17843 * convert a string to an object..
17844 * eg. 'AAA.BBB' -> finds AAA.BBB
17848 toObject : function(str)
17850 if (!str || typeof(str) == 'object') {
17853 if (str.substring(0,1) == '#') {
17857 var ar = str.split('.');
17862 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17864 throw "Module not found : " + str;
17868 throw "Module not found : " + str;
17870 Roo.each(ar, function(e) {
17871 if (typeof(o[e]) == 'undefined') {
17872 throw "Module not found : " + str;
17883 * move modules into their correct place in the tree..
17886 preBuild : function ()
17889 Roo.each(this.modules , function (obj)
17891 Roo.XComponent.event.fireEvent('beforebuild', obj);
17893 var opar = obj.parent;
17895 obj.parent = this.toObject(opar);
17897 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17902 Roo.debug && Roo.log("GOT top level module");
17903 Roo.debug && Roo.log(obj);
17904 obj.modules = new Roo.util.MixedCollection(false,
17905 function(o) { return o.order + '' }
17907 this.topModule = obj;
17910 // parent is a string (usually a dom element name..)
17911 if (typeof(obj.parent) == 'string') {
17912 this.elmodules.push(obj);
17915 if (obj.parent.constructor != Roo.XComponent) {
17916 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17918 if (!obj.parent.modules) {
17919 obj.parent.modules = new Roo.util.MixedCollection(false,
17920 function(o) { return o.order + '' }
17923 if (obj.parent.disabled) {
17924 obj.disabled = true;
17926 obj.parent.modules.add(obj);
17931 * make a list of modules to build.
17932 * @return {Array} list of modules.
17935 buildOrder : function()
17938 var cmp = function(a,b) {
17939 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17941 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17942 throw "No top level modules to build";
17945 // make a flat list in order of modules to build.
17946 var mods = this.topModule ? [ this.topModule ] : [];
17949 // elmodules (is a list of DOM based modules )
17950 Roo.each(this.elmodules, function(e) {
17952 if (!this.topModule &&
17953 typeof(e.parent) == 'string' &&
17954 e.parent.substring(0,1) == '#' &&
17955 Roo.get(e.parent.substr(1))
17958 _this.topModule = e;
17964 // add modules to their parents..
17965 var addMod = function(m) {
17966 Roo.debug && Roo.log("build Order: add: " + m.name);
17969 if (m.modules && !m.disabled) {
17970 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17971 m.modules.keySort('ASC', cmp );
17972 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17974 m.modules.each(addMod);
17976 Roo.debug && Roo.log("build Order: no child modules");
17978 // not sure if this is used any more..
17980 m.finalize.name = m.name + " (clean up) ";
17981 mods.push(m.finalize);
17985 if (this.topModule && this.topModule.modules) {
17986 this.topModule.modules.keySort('ASC', cmp );
17987 this.topModule.modules.each(addMod);
17993 * Build the registered modules.
17994 * @param {Object} parent element.
17995 * @param {Function} optional method to call after module has been added.
17999 build : function(opts)
18002 if (typeof(opts) != 'undefined') {
18003 Roo.apply(this,opts);
18007 var mods = this.buildOrder();
18009 //this.allmods = mods;
18010 //Roo.debug && Roo.log(mods);
18012 if (!mods.length) { // should not happen
18013 throw "NO modules!!!";
18017 var msg = "Building Interface...";
18018 // flash it up as modal - so we store the mask!?
18019 if (!this.hideProgress && Roo.MessageBox) {
18020 Roo.MessageBox.show({ title: 'loading' });
18021 Roo.MessageBox.show({
18022 title: "Please wait...",
18032 var total = mods.length;
18035 var progressRun = function() {
18036 if (!mods.length) {
18037 Roo.debug && Roo.log('hide?');
18038 if (!this.hideProgress && Roo.MessageBox) {
18039 Roo.MessageBox.hide();
18041 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18043 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18049 var m = mods.shift();
18052 Roo.debug && Roo.log(m);
18053 // not sure if this is supported any more.. - modules that are are just function
18054 if (typeof(m) == 'function') {
18056 return progressRun.defer(10, _this);
18060 msg = "Building Interface " + (total - mods.length) +
18062 (m.name ? (' - ' + m.name) : '');
18063 Roo.debug && Roo.log(msg);
18064 if (!_this.hideProgress && Roo.MessageBox) {
18065 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
18069 // is the module disabled?
18070 var disabled = (typeof(m.disabled) == 'function') ?
18071 m.disabled.call(m.module.disabled) : m.disabled;
18075 return progressRun(); // we do not update the display!
18083 // it's 10 on top level, and 1 on others??? why...
18084 return progressRun.defer(10, _this);
18087 progressRun.defer(1, _this);
18093 * Overlay a set of modified strings onto a component
18094 * This is dependant on our builder exporting the strings and 'named strings' elements.
18096 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18097 * @param {Object} associative array of 'named' string and it's new value.
18100 overlayStrings : function( component, strings )
18102 if (typeof(component['_named_strings']) == 'undefined') {
18103 throw "ERROR: component does not have _named_strings";
18105 for ( var k in strings ) {
18106 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18107 if (md !== false) {
18108 component['_strings'][md] = strings[k];
18110 Roo.log('could not find named string: ' + k + ' in');
18111 Roo.log(component);
18126 * wrapper for event.on - aliased later..
18127 * Typically use to register a event handler for register:
18129 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18138 Roo.XComponent.event = new Roo.util.Observable({
18142 * Fires when an Component is registered,
18143 * set the disable property on the Component to stop registration.
18144 * @param {Roo.XComponent} c the component being registerd.
18149 * @event beforebuild
18150 * Fires before each Component is built
18151 * can be used to apply permissions.
18152 * @param {Roo.XComponent} c the component being registerd.
18155 'beforebuild' : true,
18157 * @event buildcomplete
18158 * Fires on the top level element when all elements have been built
18159 * @param {Roo.XComponent} the top level component.
18161 'buildcomplete' : true
18166 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
18169 * marked - a markdown parser
18170 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18171 * https://github.com/chjj/marked
18177 * Roo.Markdown - is a very crude wrapper around marked..
18181 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18183 * Note: move the sample code to the bottom of this
18184 * file before uncommenting it.
18189 Roo.Markdown.toHtml = function(text) {
18191 var c = new Roo.Markdown.marked.setOptions({
18192 renderer: new Roo.Markdown.marked.Renderer(),
18203 text = text.replace(/\\\n/g,' ');
18204 return Roo.Markdown.marked(text);
18209 // Wraps all "globals" so that the only thing
18210 // exposed is makeHtml().
18216 * eval:var:unescape
18224 var escape = function (html, encode) {
18226 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
18227 .replace(/</g, '<')
18228 .replace(/>/g, '>')
18229 .replace(/"/g, '"')
18230 .replace(/'/g, ''');
18233 var unescape = function (html) {
18234 // explicitly match decimal, hex, and named HTML entities
18235 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18236 n = n.toLowerCase();
18237 if (n === 'colon') { return ':'; }
18238 if (n.charAt(0) === '#') {
18239 return n.charAt(1) === 'x'
18240 ? String.fromCharCode(parseInt(n.substring(2), 16))
18241 : String.fromCharCode(+n.substring(1));
18247 var replace = function (regex, opt) {
18248 regex = regex.source;
18250 return function self(name, val) {
18251 if (!name) { return new RegExp(regex, opt); }
18252 val = val.source || val;
18253 val = val.replace(/(^|[^\[])\^/g, '$1');
18254 regex = regex.replace(name, val);
18263 var noop = function () {}
18269 var merge = function (obj) {
18274 for (; i < arguments.length; i++) {
18275 target = arguments[i];
18276 for (key in target) {
18277 if (Object.prototype.hasOwnProperty.call(target, key)) {
18278 obj[key] = target[key];
18288 * Block-Level Grammar
18296 code: /^( {4}[^\n]+\n*)+/,
18298 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18299 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18301 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18302 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18303 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18304 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18305 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18307 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18311 block.bullet = /(?:[*+-]|\d+\.)/;
18312 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18313 block.item = replace(block.item, 'gm')
18314 (/bull/g, block.bullet)
18317 block.list = replace(block.list)
18318 (/bull/g, block.bullet)
18319 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18320 ('def', '\\n+(?=' + block.def.source + ')')
18323 block.blockquote = replace(block.blockquote)
18327 block._tag = '(?!(?:'
18328 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18329 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18330 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18332 block.html = replace(block.html)
18333 ('comment', /<!--[\s\S]*?-->/)
18334 ('closed', /<(tag)[\s\S]+?<\/\1>/)
18335 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18336 (/tag/g, block._tag)
18339 block.paragraph = replace(block.paragraph)
18341 ('heading', block.heading)
18342 ('lheading', block.lheading)
18343 ('blockquote', block.blockquote)
18344 ('tag', '<' + block._tag)
18349 * Normal Block Grammar
18352 block.normal = merge({}, block);
18355 * GFM Block Grammar
18358 block.gfm = merge({}, block.normal, {
18359 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18361 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18364 block.gfm.paragraph = replace(block.paragraph)
18366 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18367 + block.list.source.replace('\\1', '\\3') + '|')
18371 * GFM + Tables Block Grammar
18374 block.tables = merge({}, block.gfm, {
18375 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18376 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18383 var Lexer = function (options) {
18385 this.tokens.links = {};
18386 this.options = options || marked.defaults;
18387 this.rules = block.normal;
18389 if (this.options.gfm) {
18390 if (this.options.tables) {
18391 this.rules = block.tables;
18393 this.rules = block.gfm;
18399 * Expose Block Rules
18402 Lexer.rules = block;
18405 * Static Lex Method
18408 Lexer.lex = function(src, options) {
18409 var lexer = new Lexer(options);
18410 return lexer.lex(src);
18417 Lexer.prototype.lex = function(src) {
18419 .replace(/\r\n|\r/g, '\n')
18420 .replace(/\t/g, ' ')
18421 .replace(/\u00a0/g, ' ')
18422 .replace(/\u2424/g, '\n');
18424 return this.token(src, true);
18431 Lexer.prototype.token = function(src, top, bq) {
18432 var src = src.replace(/^ +$/gm, '')
18445 if (cap = this.rules.newline.exec(src)) {
18446 src = src.substring(cap[0].length);
18447 if (cap[0].length > 1) {
18455 if (cap = this.rules.code.exec(src)) {
18456 src = src.substring(cap[0].length);
18457 cap = cap[0].replace(/^ {4}/gm, '');
18460 text: !this.options.pedantic
18461 ? cap.replace(/\n+$/, '')
18468 if (cap = this.rules.fences.exec(src)) {
18469 src = src.substring(cap[0].length);
18479 if (cap = this.rules.heading.exec(src)) {
18480 src = src.substring(cap[0].length);
18483 depth: cap[1].length,
18489 // table no leading pipe (gfm)
18490 if (top && (cap = this.rules.nptable.exec(src))) {
18491 src = src.substring(cap[0].length);
18495 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18496 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18497 cells: cap[3].replace(/\n$/, '').split('\n')
18500 for (i = 0; i < item.align.length; i++) {
18501 if (/^ *-+: *$/.test(item.align[i])) {
18502 item.align[i] = 'right';
18503 } else if (/^ *:-+: *$/.test(item.align[i])) {
18504 item.align[i] = 'center';
18505 } else if (/^ *:-+ *$/.test(item.align[i])) {
18506 item.align[i] = 'left';
18508 item.align[i] = null;
18512 for (i = 0; i < item.cells.length; i++) {
18513 item.cells[i] = item.cells[i].split(/ *\| */);
18516 this.tokens.push(item);
18522 if (cap = this.rules.lheading.exec(src)) {
18523 src = src.substring(cap[0].length);
18526 depth: cap[2] === '=' ? 1 : 2,
18533 if (cap = this.rules.hr.exec(src)) {
18534 src = src.substring(cap[0].length);
18542 if (cap = this.rules.blockquote.exec(src)) {
18543 src = src.substring(cap[0].length);
18546 type: 'blockquote_start'
18549 cap = cap[0].replace(/^ *> ?/gm, '');
18551 // Pass `top` to keep the current
18552 // "toplevel" state. This is exactly
18553 // how markdown.pl works.
18554 this.token(cap, top, true);
18557 type: 'blockquote_end'
18564 if (cap = this.rules.list.exec(src)) {
18565 src = src.substring(cap[0].length);
18569 type: 'list_start',
18570 ordered: bull.length > 1
18573 // Get each top-level item.
18574 cap = cap[0].match(this.rules.item);
18580 for (; i < l; i++) {
18583 // Remove the list item's bullet
18584 // so it is seen as the next token.
18585 space = item.length;
18586 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18588 // Outdent whatever the
18589 // list item contains. Hacky.
18590 if (~item.indexOf('\n ')) {
18591 space -= item.length;
18592 item = !this.options.pedantic
18593 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18594 : item.replace(/^ {1,4}/gm, '');
18597 // Determine whether the next list item belongs here.
18598 // Backpedal if it does not belong in this list.
18599 if (this.options.smartLists && i !== l - 1) {
18600 b = block.bullet.exec(cap[i + 1])[0];
18601 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18602 src = cap.slice(i + 1).join('\n') + src;
18607 // Determine whether item is loose or not.
18608 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18609 // for discount behavior.
18610 loose = next || /\n\n(?!\s*$)/.test(item);
18612 next = item.charAt(item.length - 1) === '\n';
18613 if (!loose) { loose = next; }
18618 ? 'loose_item_start'
18619 : 'list_item_start'
18623 this.token(item, false, bq);
18626 type: 'list_item_end'
18638 if (cap = this.rules.html.exec(src)) {
18639 src = src.substring(cap[0].length);
18641 type: this.options.sanitize
18644 pre: !this.options.sanitizer
18645 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
18652 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
18653 src = src.substring(cap[0].length);
18654 this.tokens.links[cap[1].toLowerCase()] = {
18662 if (top && (cap = this.rules.table.exec(src))) {
18663 src = src.substring(cap[0].length);
18667 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18668 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18669 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18672 for (i = 0; i < item.align.length; i++) {
18673 if (/^ *-+: *$/.test(item.align[i])) {
18674 item.align[i] = 'right';
18675 } else if (/^ *:-+: *$/.test(item.align[i])) {
18676 item.align[i] = 'center';
18677 } else if (/^ *:-+ *$/.test(item.align[i])) {
18678 item.align[i] = 'left';
18680 item.align[i] = null;
18684 for (i = 0; i < item.cells.length; i++) {
18685 item.cells[i] = item.cells[i]
18686 .replace(/^ *\| *| *\| *$/g, '')
18690 this.tokens.push(item);
18695 // top-level paragraph
18696 if (top && (cap = this.rules.paragraph.exec(src))) {
18697 src = src.substring(cap[0].length);
18700 text: cap[1].charAt(cap[1].length - 1) === '\n'
18701 ? cap[1].slice(0, -1)
18708 if (cap = this.rules.text.exec(src)) {
18709 // Top-level should never reach here.
18710 src = src.substring(cap[0].length);
18720 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18724 return this.tokens;
18728 * Inline-Level Grammar
18732 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18733 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18735 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18736 link: /^!?\[(inside)\]\(href\)/,
18737 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18738 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18739 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18740 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18741 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18742 br: /^ {2,}\n(?!\s*$)/,
18744 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18747 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18748 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18750 inline.link = replace(inline.link)
18751 ('inside', inline._inside)
18752 ('href', inline._href)
18755 inline.reflink = replace(inline.reflink)
18756 ('inside', inline._inside)
18760 * Normal Inline Grammar
18763 inline.normal = merge({}, inline);
18766 * Pedantic Inline Grammar
18769 inline.pedantic = merge({}, inline.normal, {
18770 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18771 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18775 * GFM Inline Grammar
18778 inline.gfm = merge({}, inline.normal, {
18779 escape: replace(inline.escape)('])', '~|])')(),
18780 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18781 del: /^~~(?=\S)([\s\S]*?\S)~~/,
18782 text: replace(inline.text)
18784 ('|', '|https?://|')
18789 * GFM + Line Breaks Inline Grammar
18792 inline.breaks = merge({}, inline.gfm, {
18793 br: replace(inline.br)('{2,}', '*')(),
18794 text: replace(inline.gfm.text)('{2,}', '*')()
18798 * Inline Lexer & Compiler
18801 var InlineLexer = function (links, options) {
18802 this.options = options || marked.defaults;
18803 this.links = links;
18804 this.rules = inline.normal;
18805 this.renderer = this.options.renderer || new Renderer;
18806 this.renderer.options = this.options;
18810 Error('Tokens array requires a `links` property.');
18813 if (this.options.gfm) {
18814 if (this.options.breaks) {
18815 this.rules = inline.breaks;
18817 this.rules = inline.gfm;
18819 } else if (this.options.pedantic) {
18820 this.rules = inline.pedantic;
18825 * Expose Inline Rules
18828 InlineLexer.rules = inline;
18831 * Static Lexing/Compiling Method
18834 InlineLexer.output = function(src, links, options) {
18835 var inline = new InlineLexer(links, options);
18836 return inline.output(src);
18843 InlineLexer.prototype.output = function(src) {
18852 if (cap = this.rules.escape.exec(src)) {
18853 src = src.substring(cap[0].length);
18859 if (cap = this.rules.autolink.exec(src)) {
18860 src = src.substring(cap[0].length);
18861 if (cap[2] === '@') {
18862 text = cap[1].charAt(6) === ':'
18863 ? this.mangle(cap[1].substring(7))
18864 : this.mangle(cap[1]);
18865 href = this.mangle('mailto:') + text;
18867 text = escape(cap[1]);
18870 out += this.renderer.link(href, null, text);
18875 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18876 src = src.substring(cap[0].length);
18877 text = escape(cap[1]);
18879 out += this.renderer.link(href, null, text);
18884 if (cap = this.rules.tag.exec(src)) {
18885 if (!this.inLink && /^<a /i.test(cap[0])) {
18886 this.inLink = true;
18887 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18888 this.inLink = false;
18890 src = src.substring(cap[0].length);
18891 out += this.options.sanitize
18892 ? this.options.sanitizer
18893 ? this.options.sanitizer(cap[0])
18900 if (cap = this.rules.link.exec(src)) {
18901 src = src.substring(cap[0].length);
18902 this.inLink = true;
18903 out += this.outputLink(cap, {
18907 this.inLink = false;
18912 if ((cap = this.rules.reflink.exec(src))
18913 || (cap = this.rules.nolink.exec(src))) {
18914 src = src.substring(cap[0].length);
18915 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18916 link = this.links[link.toLowerCase()];
18917 if (!link || !link.href) {
18918 out += cap[0].charAt(0);
18919 src = cap[0].substring(1) + src;
18922 this.inLink = true;
18923 out += this.outputLink(cap, link);
18924 this.inLink = false;
18929 if (cap = this.rules.strong.exec(src)) {
18930 src = src.substring(cap[0].length);
18931 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18936 if (cap = this.rules.em.exec(src)) {
18937 src = src.substring(cap[0].length);
18938 out += this.renderer.em(this.output(cap[2] || cap[1]));
18943 if (cap = this.rules.code.exec(src)) {
18944 src = src.substring(cap[0].length);
18945 out += this.renderer.codespan(escape(cap[2], true));
18950 if (cap = this.rules.br.exec(src)) {
18951 src = src.substring(cap[0].length);
18952 out += this.renderer.br();
18957 if (cap = this.rules.del.exec(src)) {
18958 src = src.substring(cap[0].length);
18959 out += this.renderer.del(this.output(cap[1]));
18964 if (cap = this.rules.text.exec(src)) {
18965 src = src.substring(cap[0].length);
18966 out += this.renderer.text(escape(this.smartypants(cap[0])));
18972 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18983 InlineLexer.prototype.outputLink = function(cap, link) {
18984 var href = escape(link.href)
18985 , title = link.title ? escape(link.title) : null;
18987 return cap[0].charAt(0) !== '!'
18988 ? this.renderer.link(href, title, this.output(cap[1]))
18989 : this.renderer.image(href, title, escape(cap[1]));
18993 * Smartypants Transformations
18996 InlineLexer.prototype.smartypants = function(text) {
18997 if (!this.options.smartypants) { return text; }
19000 .replace(/---/g, '\u2014')
19002 .replace(/--/g, '\u2013')
19004 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19005 // closing singles & apostrophes
19006 .replace(/'/g, '\u2019')
19008 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19010 .replace(/"/g, '\u201d')
19012 .replace(/\.{3}/g, '\u2026');
19019 InlineLexer.prototype.mangle = function(text) {
19020 if (!this.options.mangle) { return text; }
19026 for (; i < l; i++) {
19027 ch = text.charCodeAt(i);
19028 if (Math.random() > 0.5) {
19029 ch = 'x' + ch.toString(16);
19031 out += '&#' + ch + ';';
19042 * eval:var:Renderer
19045 var Renderer = function (options) {
19046 this.options = options || {};
19049 Renderer.prototype.code = function(code, lang, escaped) {
19050 if (this.options.highlight) {
19051 var out = this.options.highlight(code, lang);
19052 if (out != null && out !== code) {
19057 // hack!!! - it's already escapeD?
19062 return '<pre><code>'
19063 + (escaped ? code : escape(code, true))
19064 + '\n</code></pre>';
19067 return '<pre><code class="'
19068 + this.options.langPrefix
19069 + escape(lang, true)
19071 + (escaped ? code : escape(code, true))
19072 + '\n</code></pre>\n';
19075 Renderer.prototype.blockquote = function(quote) {
19076 return '<blockquote>\n' + quote + '</blockquote>\n';
19079 Renderer.prototype.html = function(html) {
19083 Renderer.prototype.heading = function(text, level, raw) {
19087 + this.options.headerPrefix
19088 + raw.toLowerCase().replace(/[^\w]+/g, '-')
19096 Renderer.prototype.hr = function() {
19097 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19100 Renderer.prototype.list = function(body, ordered) {
19101 var type = ordered ? 'ol' : 'ul';
19102 return '<' + type + '>\n' + body + '</' + type + '>\n';
19105 Renderer.prototype.listitem = function(text) {
19106 return '<li>' + text + '</li>\n';
19109 Renderer.prototype.paragraph = function(text) {
19110 return '<p>' + text + '</p>\n';
19113 Renderer.prototype.table = function(header, body) {
19114 return '<table class="table table-striped">\n'
19124 Renderer.prototype.tablerow = function(content) {
19125 return '<tr>\n' + content + '</tr>\n';
19128 Renderer.prototype.tablecell = function(content, flags) {
19129 var type = flags.header ? 'th' : 'td';
19130 var tag = flags.align
19131 ? '<' + type + ' style="text-align:' + flags.align + '">'
19132 : '<' + type + '>';
19133 return tag + content + '</' + type + '>\n';
19136 // span level renderer
19137 Renderer.prototype.strong = function(text) {
19138 return '<strong>' + text + '</strong>';
19141 Renderer.prototype.em = function(text) {
19142 return '<em>' + text + '</em>';
19145 Renderer.prototype.codespan = function(text) {
19146 return '<code>' + text + '</code>';
19149 Renderer.prototype.br = function() {
19150 return this.options.xhtml ? '<br/>' : '<br>';
19153 Renderer.prototype.del = function(text) {
19154 return '<del>' + text + '</del>';
19157 Renderer.prototype.link = function(href, title, text) {
19158 if (this.options.sanitize) {
19160 var prot = decodeURIComponent(unescape(href))
19161 .replace(/[^\w:]/g, '')
19166 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19170 var out = '<a href="' + href + '"';
19172 out += ' title="' + title + '"';
19174 out += '>' + text + '</a>';
19178 Renderer.prototype.image = function(href, title, text) {
19179 var out = '<img src="' + href + '" alt="' + text + '"';
19181 out += ' title="' + title + '"';
19183 out += this.options.xhtml ? '/>' : '>';
19187 Renderer.prototype.text = function(text) {
19192 * Parsing & Compiling
19198 var Parser= function (options) {
19201 this.options = options || marked.defaults;
19202 this.options.renderer = this.options.renderer || new Renderer;
19203 this.renderer = this.options.renderer;
19204 this.renderer.options = this.options;
19208 * Static Parse Method
19211 Parser.parse = function(src, options, renderer) {
19212 var parser = new Parser(options, renderer);
19213 return parser.parse(src);
19220 Parser.prototype.parse = function(src) {
19221 this.inline = new InlineLexer(src.links, this.options, this.renderer);
19222 this.tokens = src.reverse();
19225 while (this.next()) {
19236 Parser.prototype.next = function() {
19237 return this.token = this.tokens.pop();
19241 * Preview Next Token
19244 Parser.prototype.peek = function() {
19245 return this.tokens[this.tokens.length - 1] || 0;
19249 * Parse Text Tokens
19252 Parser.prototype.parseText = function() {
19253 var body = this.token.text;
19255 while (this.peek().type === 'text') {
19256 body += '\n' + this.next().text;
19259 return this.inline.output(body);
19263 * Parse Current Token
19266 Parser.prototype.tok = function() {
19267 switch (this.token.type) {
19272 return this.renderer.hr();
19275 return this.renderer.heading(
19276 this.inline.output(this.token.text),
19281 return this.renderer.code(this.token.text,
19283 this.token.escaped);
19296 for (i = 0; i < this.token.header.length; i++) {
19297 flags = { header: true, align: this.token.align[i] };
19298 cell += this.renderer.tablecell(
19299 this.inline.output(this.token.header[i]),
19300 { header: true, align: this.token.align[i] }
19303 header += this.renderer.tablerow(cell);
19305 for (i = 0; i < this.token.cells.length; i++) {
19306 row = this.token.cells[i];
19309 for (j = 0; j < row.length; j++) {
19310 cell += this.renderer.tablecell(
19311 this.inline.output(row[j]),
19312 { header: false, align: this.token.align[j] }
19316 body += this.renderer.tablerow(cell);
19318 return this.renderer.table(header, body);
19320 case 'blockquote_start': {
19323 while (this.next().type !== 'blockquote_end') {
19324 body += this.tok();
19327 return this.renderer.blockquote(body);
19329 case 'list_start': {
19331 , ordered = this.token.ordered;
19333 while (this.next().type !== 'list_end') {
19334 body += this.tok();
19337 return this.renderer.list(body, ordered);
19339 case 'list_item_start': {
19342 while (this.next().type !== 'list_item_end') {
19343 body += this.token.type === 'text'
19348 return this.renderer.listitem(body);
19350 case 'loose_item_start': {
19353 while (this.next().type !== 'list_item_end') {
19354 body += this.tok();
19357 return this.renderer.listitem(body);
19360 var html = !this.token.pre && !this.options.pedantic
19361 ? this.inline.output(this.token.text)
19363 return this.renderer.html(html);
19365 case 'paragraph': {
19366 return this.renderer.paragraph(this.inline.output(this.token.text));
19369 return this.renderer.paragraph(this.parseText());
19381 var marked = function (src, opt, callback) {
19382 if (callback || typeof opt === 'function') {
19388 opt = merge({}, marked.defaults, opt || {});
19390 var highlight = opt.highlight
19396 tokens = Lexer.lex(src, opt)
19398 return callback(e);
19401 pending = tokens.length;
19405 var done = function(err) {
19407 opt.highlight = highlight;
19408 return callback(err);
19414 out = Parser.parse(tokens, opt);
19419 opt.highlight = highlight;
19423 : callback(null, out);
19426 if (!highlight || highlight.length < 3) {
19430 delete opt.highlight;
19432 if (!pending) { return done(); }
19434 for (; i < tokens.length; i++) {
19436 if (token.type !== 'code') {
19437 return --pending || done();
19439 return highlight(token.text, token.lang, function(err, code) {
19440 if (err) { return done(err); }
19441 if (code == null || code === token.text) {
19442 return --pending || done();
19445 token.escaped = true;
19446 --pending || done();
19454 if (opt) { opt = merge({}, marked.defaults, opt); }
19455 return Parser.parse(Lexer.lex(src, opt), opt);
19457 e.message += '\nPlease report this to https://github.com/chjj/marked.';
19458 if ((opt || marked.defaults).silent) {
19459 return '<p>An error occured:</p><pre>'
19460 + escape(e.message + '', true)
19472 marked.setOptions = function(opt) {
19473 merge(marked.defaults, opt);
19477 marked.defaults = {
19488 langPrefix: 'lang-',
19489 smartypants: false,
19491 renderer: new Renderer,
19499 marked.Parser = Parser;
19500 marked.parser = Parser.parse;
19502 marked.Renderer = Renderer;
19504 marked.Lexer = Lexer;
19505 marked.lexer = Lexer.lex;
19507 marked.InlineLexer = InlineLexer;
19508 marked.inlineLexer = InlineLexer.output;
19510 marked.parse = marked;
19512 Roo.Markdown.marked = marked;
19516 * Ext JS Library 1.1.1
19517 * Copyright(c) 2006-2007, Ext JS, LLC.
19519 * Originally Released Under LGPL - original licence link has changed is not relivant.
19522 * <script type="text/javascript">
19528 * These classes are derivatives of the similarly named classes in the YUI Library.
19529 * The original license:
19530 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19531 * Code licensed under the BSD License:
19532 * http://developer.yahoo.net/yui/license.txt
19537 var Event=Roo.EventManager;
19538 var Dom=Roo.lib.Dom;
19541 * @class Roo.dd.DragDrop
19542 * @extends Roo.util.Observable
19543 * Defines the interface and base operation of items that that can be
19544 * dragged or can be drop targets. It was designed to be extended, overriding
19545 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19546 * Up to three html elements can be associated with a DragDrop instance:
19548 * <li>linked element: the element that is passed into the constructor.
19549 * This is the element which defines the boundaries for interaction with
19550 * other DragDrop objects.</li>
19551 * <li>handle element(s): The drag operation only occurs if the element that
19552 * was clicked matches a handle element. By default this is the linked
19553 * element, but there are times that you will want only a portion of the
19554 * linked element to initiate the drag operation, and the setHandleElId()
19555 * method provides a way to define this.</li>
19556 * <li>drag element: this represents the element that would be moved along
19557 * with the cursor during a drag operation. By default, this is the linked
19558 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
19559 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19562 * This class should not be instantiated until the onload event to ensure that
19563 * the associated elements are available.
19564 * The following would define a DragDrop obj that would interact with any
19565 * other DragDrop obj in the "group1" group:
19567 * dd = new Roo.dd.DragDrop("div1", "group1");
19569 * Since none of the event handlers have been implemented, nothing would
19570 * actually happen if you were to run the code above. Normally you would
19571 * override this class or one of the default implementations, but you can
19572 * also override the methods you want on an instance of the class...
19574 * dd.onDragDrop = function(e, id) {
19575 * alert("dd was dropped on " + id);
19579 * @param {String} id of the element that is linked to this instance
19580 * @param {String} sGroup the group of related DragDrop objects
19581 * @param {object} config an object containing configurable attributes
19582 * Valid properties for DragDrop:
19583 * padding, isTarget, maintainOffset, primaryButtonOnly
19585 Roo.dd.DragDrop = function(id, sGroup, config) {
19587 this.init(id, sGroup, config);
19592 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19595 * The id of the element associated with this object. This is what we
19596 * refer to as the "linked element" because the size and position of
19597 * this element is used to determine when the drag and drop objects have
19605 * Configuration attributes passed into the constructor
19612 * The id of the element that will be dragged. By default this is same
19613 * as the linked element , but could be changed to another element. Ex:
19615 * @property dragElId
19622 * the id of the element that initiates the drag operation. By default
19623 * this is the linked element, but could be changed to be a child of this
19624 * element. This lets us do things like only starting the drag when the
19625 * header element within the linked html element is clicked.
19626 * @property handleElId
19633 * An associative array of HTML tags that will be ignored if clicked.
19634 * @property invalidHandleTypes
19635 * @type {string: string}
19637 invalidHandleTypes: null,
19640 * An associative array of ids for elements that will be ignored if clicked
19641 * @property invalidHandleIds
19642 * @type {string: string}
19644 invalidHandleIds: null,
19647 * An indexted array of css class names for elements that will be ignored
19649 * @property invalidHandleClasses
19652 invalidHandleClasses: null,
19655 * The linked element's absolute X position at the time the drag was
19657 * @property startPageX
19664 * The linked element's absolute X position at the time the drag was
19666 * @property startPageY
19673 * The group defines a logical collection of DragDrop objects that are
19674 * related. Instances only get events when interacting with other
19675 * DragDrop object in the same group. This lets us define multiple
19676 * groups using a single DragDrop subclass if we want.
19678 * @type {string: string}
19683 * Individual drag/drop instances can be locked. This will prevent
19684 * onmousedown start drag.
19692 * Lock this instance
19695 lock: function() { this.locked = true; },
19698 * Unlock this instace
19701 unlock: function() { this.locked = false; },
19704 * By default, all insances can be a drop target. This can be disabled by
19705 * setting isTarget to false.
19712 * The padding configured for this drag and drop object for calculating
19713 * the drop zone intersection with this object.
19720 * Cached reference to the linked element
19721 * @property _domRef
19727 * Internal typeof flag
19728 * @property __ygDragDrop
19731 __ygDragDrop: true,
19734 * Set to true when horizontal contraints are applied
19735 * @property constrainX
19742 * Set to true when vertical contraints are applied
19743 * @property constrainY
19750 * The left constraint
19758 * The right constraint
19766 * The up constraint
19775 * The down constraint
19783 * Maintain offsets when we resetconstraints. Set to true when you want
19784 * the position of the element relative to its parent to stay the same
19785 * when the page changes
19787 * @property maintainOffset
19790 maintainOffset: false,
19793 * Array of pixel locations the element will snap to if we specified a
19794 * horizontal graduation/interval. This array is generated automatically
19795 * when you define a tick interval.
19802 * Array of pixel locations the element will snap to if we specified a
19803 * vertical graduation/interval. This array is generated automatically
19804 * when you define a tick interval.
19811 * By default the drag and drop instance will only respond to the primary
19812 * button click (left button for a right-handed mouse). Set to true to
19813 * allow drag and drop to start with any mouse click that is propogated
19815 * @property primaryButtonOnly
19818 primaryButtonOnly: true,
19821 * The availabe property is false until the linked dom element is accessible.
19822 * @property available
19828 * By default, drags can only be initiated if the mousedown occurs in the
19829 * region the linked element is. This is done in part to work around a
19830 * bug in some browsers that mis-report the mousedown if the previous
19831 * mouseup happened outside of the window. This property is set to true
19832 * if outer handles are defined.
19834 * @property hasOuterHandles
19838 hasOuterHandles: false,
19841 * Code that executes immediately before the startDrag event
19842 * @method b4StartDrag
19845 b4StartDrag: function(x, y) { },
19848 * Abstract method called after a drag/drop object is clicked
19849 * and the drag or mousedown time thresholds have beeen met.
19850 * @method startDrag
19851 * @param {int} X click location
19852 * @param {int} Y click location
19854 startDrag: function(x, y) { /* override this */ },
19857 * Code that executes immediately before the onDrag event
19861 b4Drag: function(e) { },
19864 * Abstract method called during the onMouseMove event while dragging an
19867 * @param {Event} e the mousemove event
19869 onDrag: function(e) { /* override this */ },
19872 * Abstract method called when this element fist begins hovering over
19873 * another DragDrop obj
19874 * @method onDragEnter
19875 * @param {Event} e the mousemove event
19876 * @param {String|DragDrop[]} id In POINT mode, the element
19877 * id this is hovering over. In INTERSECT mode, an array of one or more
19878 * dragdrop items being hovered over.
19880 onDragEnter: function(e, id) { /* override this */ },
19883 * Code that executes immediately before the onDragOver event
19884 * @method b4DragOver
19887 b4DragOver: function(e) { },
19890 * Abstract method called when this element is hovering over another
19892 * @method onDragOver
19893 * @param {Event} e the mousemove event
19894 * @param {String|DragDrop[]} id In POINT mode, the element
19895 * id this is hovering over. In INTERSECT mode, an array of dd items
19896 * being hovered over.
19898 onDragOver: function(e, id) { /* override this */ },
19901 * Code that executes immediately before the onDragOut event
19902 * @method b4DragOut
19905 b4DragOut: function(e) { },
19908 * Abstract method called when we are no longer hovering over an element
19909 * @method onDragOut
19910 * @param {Event} e the mousemove event
19911 * @param {String|DragDrop[]} id In POINT mode, the element
19912 * id this was hovering over. In INTERSECT mode, an array of dd items
19913 * that the mouse is no longer over.
19915 onDragOut: function(e, id) { /* override this */ },
19918 * Code that executes immediately before the onDragDrop event
19919 * @method b4DragDrop
19922 b4DragDrop: function(e) { },
19925 * Abstract method called when this item is dropped on another DragDrop
19927 * @method onDragDrop
19928 * @param {Event} e the mouseup event
19929 * @param {String|DragDrop[]} id In POINT mode, the element
19930 * id this was dropped on. In INTERSECT mode, an array of dd items this
19933 onDragDrop: function(e, id) { /* override this */ },
19936 * Abstract method called when this item is dropped on an area with no
19938 * @method onInvalidDrop
19939 * @param {Event} e the mouseup event
19941 onInvalidDrop: function(e) { /* override this */ },
19944 * Code that executes immediately before the endDrag event
19945 * @method b4EndDrag
19948 b4EndDrag: function(e) { },
19951 * Fired when we are done dragging the object
19953 * @param {Event} e the mouseup event
19955 endDrag: function(e) { /* override this */ },
19958 * Code executed immediately before the onMouseDown event
19959 * @method b4MouseDown
19960 * @param {Event} e the mousedown event
19963 b4MouseDown: function(e) { },
19966 * Event handler that fires when a drag/drop obj gets a mousedown
19967 * @method onMouseDown
19968 * @param {Event} e the mousedown event
19970 onMouseDown: function(e) { /* override this */ },
19973 * Event handler that fires when a drag/drop obj gets a mouseup
19974 * @method onMouseUp
19975 * @param {Event} e the mouseup event
19977 onMouseUp: function(e) { /* override this */ },
19980 * Override the onAvailable method to do what is needed after the initial
19981 * position was determined.
19982 * @method onAvailable
19984 onAvailable: function () {
19988 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19991 defaultPadding : {left:0, right:0, top:0, bottom:0},
19994 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19998 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19999 { dragElId: "existingProxyDiv" });
20000 dd.startDrag = function(){
20001 this.constrainTo("parent-id");
20004 * Or you can initalize it using the {@link Roo.Element} object:
20006 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20007 startDrag : function(){
20008 this.constrainTo("parent-id");
20012 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20013 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20014 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20015 * an object containing the sides to pad. For example: {right:10, bottom:10}
20016 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20018 constrainTo : function(constrainTo, pad, inContent){
20019 if(typeof pad == "number"){
20020 pad = {left: pad, right:pad, top:pad, bottom:pad};
20022 pad = pad || this.defaultPadding;
20023 var b = Roo.get(this.getEl()).getBox();
20024 var ce = Roo.get(constrainTo);
20025 var s = ce.getScroll();
20026 var c, cd = ce.dom;
20027 if(cd == document.body){
20028 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20031 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20035 var topSpace = b.y - c.y;
20036 var leftSpace = b.x - c.x;
20038 this.resetConstraints();
20039 this.setXConstraint(leftSpace - (pad.left||0), // left
20040 c.width - leftSpace - b.width - (pad.right||0) //right
20042 this.setYConstraint(topSpace - (pad.top||0), //top
20043 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20048 * Returns a reference to the linked element
20050 * @return {HTMLElement} the html element
20052 getEl: function() {
20053 if (!this._domRef) {
20054 this._domRef = Roo.getDom(this.id);
20057 return this._domRef;
20061 * Returns a reference to the actual element to drag. By default this is
20062 * the same as the html element, but it can be assigned to another
20063 * element. An example of this can be found in Roo.dd.DDProxy
20064 * @method getDragEl
20065 * @return {HTMLElement} the html element
20067 getDragEl: function() {
20068 return Roo.getDom(this.dragElId);
20072 * Sets up the DragDrop object. Must be called in the constructor of any
20073 * Roo.dd.DragDrop subclass
20075 * @param id the id of the linked element
20076 * @param {String} sGroup the group of related items
20077 * @param {object} config configuration attributes
20079 init: function(id, sGroup, config) {
20080 this.initTarget(id, sGroup, config);
20081 if (!Roo.isTouch) {
20082 Event.on(this.id, "mousedown", this.handleMouseDown, this);
20084 Event.on(this.id, "touchstart", this.handleMouseDown, this);
20085 // Event.on(this.id, "selectstart", Event.preventDefault);
20089 * Initializes Targeting functionality only... the object does not
20090 * get a mousedown handler.
20091 * @method initTarget
20092 * @param id the id of the linked element
20093 * @param {String} sGroup the group of related items
20094 * @param {object} config configuration attributes
20096 initTarget: function(id, sGroup, config) {
20098 // configuration attributes
20099 this.config = config || {};
20101 // create a local reference to the drag and drop manager
20102 this.DDM = Roo.dd.DDM;
20103 // initialize the groups array
20106 // assume that we have an element reference instead of an id if the
20107 // parameter is not a string
20108 if (typeof id !== "string") {
20115 // add to an interaction group
20116 this.addToGroup((sGroup) ? sGroup : "default");
20118 // We don't want to register this as the handle with the manager
20119 // so we just set the id rather than calling the setter.
20120 this.handleElId = id;
20122 // the linked element is the element that gets dragged by default
20123 this.setDragElId(id);
20125 // by default, clicked anchors will not start drag operations.
20126 this.invalidHandleTypes = { A: "A" };
20127 this.invalidHandleIds = {};
20128 this.invalidHandleClasses = [];
20130 this.applyConfig();
20132 this.handleOnAvailable();
20136 * Applies the configuration parameters that were passed into the constructor.
20137 * This is supposed to happen at each level through the inheritance chain. So
20138 * a DDProxy implentation will execute apply config on DDProxy, DD, and
20139 * DragDrop in order to get all of the parameters that are available in
20141 * @method applyConfig
20143 applyConfig: function() {
20145 // configurable properties:
20146 // padding, isTarget, maintainOffset, primaryButtonOnly
20147 this.padding = this.config.padding || [0, 0, 0, 0];
20148 this.isTarget = (this.config.isTarget !== false);
20149 this.maintainOffset = (this.config.maintainOffset);
20150 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20155 * Executed when the linked element is available
20156 * @method handleOnAvailable
20159 handleOnAvailable: function() {
20160 this.available = true;
20161 this.resetConstraints();
20162 this.onAvailable();
20166 * Configures the padding for the target zone in px. Effectively expands
20167 * (or reduces) the virtual object size for targeting calculations.
20168 * Supports css-style shorthand; if only one parameter is passed, all sides
20169 * will have that padding, and if only two are passed, the top and bottom
20170 * will have the first param, the left and right the second.
20171 * @method setPadding
20172 * @param {int} iTop Top pad
20173 * @param {int} iRight Right pad
20174 * @param {int} iBot Bot pad
20175 * @param {int} iLeft Left pad
20177 setPadding: function(iTop, iRight, iBot, iLeft) {
20178 // this.padding = [iLeft, iRight, iTop, iBot];
20179 if (!iRight && 0 !== iRight) {
20180 this.padding = [iTop, iTop, iTop, iTop];
20181 } else if (!iBot && 0 !== iBot) {
20182 this.padding = [iTop, iRight, iTop, iRight];
20184 this.padding = [iTop, iRight, iBot, iLeft];
20189 * Stores the initial placement of the linked element.
20190 * @method setInitialPosition
20191 * @param {int} diffX the X offset, default 0
20192 * @param {int} diffY the Y offset, default 0
20194 setInitPosition: function(diffX, diffY) {
20195 var el = this.getEl();
20197 if (!this.DDM.verifyEl(el)) {
20201 var dx = diffX || 0;
20202 var dy = diffY || 0;
20204 var p = Dom.getXY( el );
20206 this.initPageX = p[0] - dx;
20207 this.initPageY = p[1] - dy;
20209 this.lastPageX = p[0];
20210 this.lastPageY = p[1];
20213 this.setStartPosition(p);
20217 * Sets the start position of the element. This is set when the obj
20218 * is initialized, the reset when a drag is started.
20219 * @method setStartPosition
20220 * @param pos current position (from previous lookup)
20223 setStartPosition: function(pos) {
20224 var p = pos || Dom.getXY( this.getEl() );
20225 this.deltaSetXY = null;
20227 this.startPageX = p[0];
20228 this.startPageY = p[1];
20232 * Add this instance to a group of related drag/drop objects. All
20233 * instances belong to at least one group, and can belong to as many
20234 * groups as needed.
20235 * @method addToGroup
20236 * @param sGroup {string} the name of the group
20238 addToGroup: function(sGroup) {
20239 this.groups[sGroup] = true;
20240 this.DDM.regDragDrop(this, sGroup);
20244 * Remove's this instance from the supplied interaction group
20245 * @method removeFromGroup
20246 * @param {string} sGroup The group to drop
20248 removeFromGroup: function(sGroup) {
20249 if (this.groups[sGroup]) {
20250 delete this.groups[sGroup];
20253 this.DDM.removeDDFromGroup(this, sGroup);
20257 * Allows you to specify that an element other than the linked element
20258 * will be moved with the cursor during a drag
20259 * @method setDragElId
20260 * @param id {string} the id of the element that will be used to initiate the drag
20262 setDragElId: function(id) {
20263 this.dragElId = id;
20267 * Allows you to specify a child of the linked element that should be
20268 * used to initiate the drag operation. An example of this would be if
20269 * you have a content div with text and links. Clicking anywhere in the
20270 * content area would normally start the drag operation. Use this method
20271 * to specify that an element inside of the content div is the element
20272 * that starts the drag operation.
20273 * @method setHandleElId
20274 * @param id {string} the id of the element that will be used to
20275 * initiate the drag.
20277 setHandleElId: function(id) {
20278 if (typeof id !== "string") {
20281 this.handleElId = id;
20282 this.DDM.regHandle(this.id, id);
20286 * Allows you to set an element outside of the linked element as a drag
20288 * @method setOuterHandleElId
20289 * @param id the id of the element that will be used to initiate the drag
20291 setOuterHandleElId: function(id) {
20292 if (typeof id !== "string") {
20295 Event.on(id, "mousedown",
20296 this.handleMouseDown, this);
20297 this.setHandleElId(id);
20299 this.hasOuterHandles = true;
20303 * Remove all drag and drop hooks for this element
20306 unreg: function() {
20307 Event.un(this.id, "mousedown",
20308 this.handleMouseDown);
20309 Event.un(this.id, "touchstart",
20310 this.handleMouseDown);
20311 this._domRef = null;
20312 this.DDM._remove(this);
20315 destroy : function(){
20320 * Returns true if this instance is locked, or the drag drop mgr is locked
20321 * (meaning that all drag/drop is disabled on the page.)
20323 * @return {boolean} true if this obj or all drag/drop is locked, else
20326 isLocked: function() {
20327 return (this.DDM.isLocked() || this.locked);
20331 * Fired when this object is clicked
20332 * @method handleMouseDown
20334 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20337 handleMouseDown: function(e, oDD){
20339 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20340 //Roo.log('not touch/ button !=0');
20343 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20344 return; // double touch..
20348 if (this.isLocked()) {
20349 //Roo.log('locked');
20353 this.DDM.refreshCache(this.groups);
20354 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20355 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20356 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
20357 //Roo.log('no outer handes or not over target');
20360 // Roo.log('check validator');
20361 if (this.clickValidator(e)) {
20362 // Roo.log('validate success');
20363 // set the initial element position
20364 this.setStartPosition();
20367 this.b4MouseDown(e);
20368 this.onMouseDown(e);
20370 this.DDM.handleMouseDown(e, this);
20372 this.DDM.stopEvent(e);
20380 clickValidator: function(e) {
20381 var target = e.getTarget();
20382 return ( this.isValidHandleChild(target) &&
20383 (this.id == this.handleElId ||
20384 this.DDM.handleWasClicked(target, this.id)) );
20388 * Allows you to specify a tag name that should not start a drag operation
20389 * when clicked. This is designed to facilitate embedding links within a
20390 * drag handle that do something other than start the drag.
20391 * @method addInvalidHandleType
20392 * @param {string} tagName the type of element to exclude
20394 addInvalidHandleType: function(tagName) {
20395 var type = tagName.toUpperCase();
20396 this.invalidHandleTypes[type] = type;
20400 * Lets you to specify an element id for a child of a drag handle
20401 * that should not initiate a drag
20402 * @method addInvalidHandleId
20403 * @param {string} id the element id of the element you wish to ignore
20405 addInvalidHandleId: function(id) {
20406 if (typeof id !== "string") {
20409 this.invalidHandleIds[id] = id;
20413 * Lets you specify a css class of elements that will not initiate a drag
20414 * @method addInvalidHandleClass
20415 * @param {string} cssClass the class of the elements you wish to ignore
20417 addInvalidHandleClass: function(cssClass) {
20418 this.invalidHandleClasses.push(cssClass);
20422 * Unsets an excluded tag name set by addInvalidHandleType
20423 * @method removeInvalidHandleType
20424 * @param {string} tagName the type of element to unexclude
20426 removeInvalidHandleType: function(tagName) {
20427 var type = tagName.toUpperCase();
20428 // this.invalidHandleTypes[type] = null;
20429 delete this.invalidHandleTypes[type];
20433 * Unsets an invalid handle id
20434 * @method removeInvalidHandleId
20435 * @param {string} id the id of the element to re-enable
20437 removeInvalidHandleId: function(id) {
20438 if (typeof id !== "string") {
20441 delete this.invalidHandleIds[id];
20445 * Unsets an invalid css class
20446 * @method removeInvalidHandleClass
20447 * @param {string} cssClass the class of the element(s) you wish to
20450 removeInvalidHandleClass: function(cssClass) {
20451 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20452 if (this.invalidHandleClasses[i] == cssClass) {
20453 delete this.invalidHandleClasses[i];
20459 * Checks the tag exclusion list to see if this click should be ignored
20460 * @method isValidHandleChild
20461 * @param {HTMLElement} node the HTMLElement to evaluate
20462 * @return {boolean} true if this is a valid tag type, false if not
20464 isValidHandleChild: function(node) {
20467 // var n = (node.nodeName == "#text") ? node.parentNode : node;
20470 nodeName = node.nodeName.toUpperCase();
20472 nodeName = node.nodeName;
20474 valid = valid && !this.invalidHandleTypes[nodeName];
20475 valid = valid && !this.invalidHandleIds[node.id];
20477 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20478 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20487 * Create the array of horizontal tick marks if an interval was specified
20488 * in setXConstraint().
20489 * @method setXTicks
20492 setXTicks: function(iStartX, iTickSize) {
20494 this.xTickSize = iTickSize;
20498 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20500 this.xTicks[this.xTicks.length] = i;
20505 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20507 this.xTicks[this.xTicks.length] = i;
20512 this.xTicks.sort(this.DDM.numericSort) ;
20516 * Create the array of vertical tick marks if an interval was specified in
20517 * setYConstraint().
20518 * @method setYTicks
20521 setYTicks: function(iStartY, iTickSize) {
20523 this.yTickSize = iTickSize;
20527 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20529 this.yTicks[this.yTicks.length] = i;
20534 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20536 this.yTicks[this.yTicks.length] = i;
20541 this.yTicks.sort(this.DDM.numericSort) ;
20545 * By default, the element can be dragged any place on the screen. Use
20546 * this method to limit the horizontal travel of the element. Pass in
20547 * 0,0 for the parameters if you want to lock the drag to the y axis.
20548 * @method setXConstraint
20549 * @param {int} iLeft the number of pixels the element can move to the left
20550 * @param {int} iRight the number of pixels the element can move to the
20552 * @param {int} iTickSize optional parameter for specifying that the
20554 * should move iTickSize pixels at a time.
20556 setXConstraint: function(iLeft, iRight, iTickSize) {
20557 this.leftConstraint = iLeft;
20558 this.rightConstraint = iRight;
20560 this.minX = this.initPageX - iLeft;
20561 this.maxX = this.initPageX + iRight;
20562 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20564 this.constrainX = true;
20568 * Clears any constraints applied to this instance. Also clears ticks
20569 * since they can't exist independent of a constraint at this time.
20570 * @method clearConstraints
20572 clearConstraints: function() {
20573 this.constrainX = false;
20574 this.constrainY = false;
20579 * Clears any tick interval defined for this instance
20580 * @method clearTicks
20582 clearTicks: function() {
20583 this.xTicks = null;
20584 this.yTicks = null;
20585 this.xTickSize = 0;
20586 this.yTickSize = 0;
20590 * By default, the element can be dragged any place on the screen. Set
20591 * this to limit the vertical travel of the element. Pass in 0,0 for the
20592 * parameters if you want to lock the drag to the x axis.
20593 * @method setYConstraint
20594 * @param {int} iUp the number of pixels the element can move up
20595 * @param {int} iDown the number of pixels the element can move down
20596 * @param {int} iTickSize optional parameter for specifying that the
20597 * element should move iTickSize pixels at a time.
20599 setYConstraint: function(iUp, iDown, iTickSize) {
20600 this.topConstraint = iUp;
20601 this.bottomConstraint = iDown;
20603 this.minY = this.initPageY - iUp;
20604 this.maxY = this.initPageY + iDown;
20605 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
20607 this.constrainY = true;
20612 * resetConstraints must be called if you manually reposition a dd element.
20613 * @method resetConstraints
20614 * @param {boolean} maintainOffset
20616 resetConstraints: function() {
20619 // Maintain offsets if necessary
20620 if (this.initPageX || this.initPageX === 0) {
20621 // figure out how much this thing has moved
20622 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
20623 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
20625 this.setInitPosition(dx, dy);
20627 // This is the first time we have detected the element's position
20629 this.setInitPosition();
20632 if (this.constrainX) {
20633 this.setXConstraint( this.leftConstraint,
20634 this.rightConstraint,
20638 if (this.constrainY) {
20639 this.setYConstraint( this.topConstraint,
20640 this.bottomConstraint,
20646 * Normally the drag element is moved pixel by pixel, but we can specify
20647 * that it move a number of pixels at a time. This method resolves the
20648 * location when we have it set up like this.
20650 * @param {int} val where we want to place the object
20651 * @param {int[]} tickArray sorted array of valid points
20652 * @return {int} the closest tick
20655 getTick: function(val, tickArray) {
20658 // If tick interval is not defined, it is effectively 1 pixel,
20659 // so we return the value passed to us.
20661 } else if (tickArray[0] >= val) {
20662 // The value is lower than the first tick, so we return the first
20664 return tickArray[0];
20666 for (var i=0, len=tickArray.length; i<len; ++i) {
20668 if (tickArray[next] && tickArray[next] >= val) {
20669 var diff1 = val - tickArray[i];
20670 var diff2 = tickArray[next] - val;
20671 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
20675 // The value is larger than the last tick, so we return the last
20677 return tickArray[tickArray.length - 1];
20684 * @return {string} string representation of the dd obj
20686 toString: function() {
20687 return ("DragDrop " + this.id);
20695 * Ext JS Library 1.1.1
20696 * Copyright(c) 2006-2007, Ext JS, LLC.
20698 * Originally Released Under LGPL - original licence link has changed is not relivant.
20701 * <script type="text/javascript">
20706 * The drag and drop utility provides a framework for building drag and drop
20707 * applications. In addition to enabling drag and drop for specific elements,
20708 * the drag and drop elements are tracked by the manager class, and the
20709 * interactions between the various elements are tracked during the drag and
20710 * the implementing code is notified about these important moments.
20713 // Only load the library once. Rewriting the manager class would orphan
20714 // existing drag and drop instances.
20715 if (!Roo.dd.DragDropMgr) {
20718 * @class Roo.dd.DragDropMgr
20719 * DragDropMgr is a singleton that tracks the element interaction for
20720 * all DragDrop items in the window. Generally, you will not call
20721 * this class directly, but it does have helper methods that could
20722 * be useful in your DragDrop implementations.
20725 Roo.dd.DragDropMgr = function() {
20727 var Event = Roo.EventManager;
20732 * Two dimensional Array of registered DragDrop objects. The first
20733 * dimension is the DragDrop item group, the second the DragDrop
20736 * @type {string: string}
20743 * Array of element ids defined as drag handles. Used to determine
20744 * if the element that generated the mousedown event is actually the
20745 * handle and not the html element itself.
20746 * @property handleIds
20747 * @type {string: string}
20754 * the DragDrop object that is currently being dragged
20755 * @property dragCurrent
20763 * the DragDrop object(s) that are being hovered over
20764 * @property dragOvers
20772 * the X distance between the cursor and the object being dragged
20781 * the Y distance between the cursor and the object being dragged
20790 * Flag to determine if we should prevent the default behavior of the
20791 * events we define. By default this is true, but this can be set to
20792 * false if you need the default behavior (not recommended)
20793 * @property preventDefault
20797 preventDefault: true,
20800 * Flag to determine if we should stop the propagation of the events
20801 * we generate. This is true by default but you may want to set it to
20802 * false if the html element contains other features that require the
20804 * @property stopPropagation
20808 stopPropagation: true,
20811 * Internal flag that is set to true when drag and drop has been
20813 * @property initialized
20820 * All drag and drop can be disabled.
20828 * Called the first time an element is registered.
20834 this.initialized = true;
20838 * In point mode, drag and drop interaction is defined by the
20839 * location of the cursor during the drag/drop
20847 * In intersect mode, drag and drop interactio nis defined by the
20848 * overlap of two or more drag and drop objects.
20849 * @property INTERSECT
20856 * The current drag and drop mode. Default: POINT
20864 * Runs method on all drag and drop objects
20865 * @method _execOnAll
20869 _execOnAll: function(sMethod, args) {
20870 for (var i in this.ids) {
20871 for (var j in this.ids[i]) {
20872 var oDD = this.ids[i][j];
20873 if (! this.isTypeOfDD(oDD)) {
20876 oDD[sMethod].apply(oDD, args);
20882 * Drag and drop initialization. Sets up the global event handlers
20887 _onLoad: function() {
20891 if (!Roo.isTouch) {
20892 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20893 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20895 Event.on(document, "touchend", this.handleMouseUp, this, true);
20896 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20898 Event.on(window, "unload", this._onUnload, this, true);
20899 Event.on(window, "resize", this._onResize, this, true);
20900 // Event.on(window, "mouseout", this._test);
20905 * Reset constraints on all drag and drop objs
20906 * @method _onResize
20910 _onResize: function(e) {
20911 this._execOnAll("resetConstraints", []);
20915 * Lock all drag and drop functionality
20919 lock: function() { this.locked = true; },
20922 * Unlock all drag and drop functionality
20926 unlock: function() { this.locked = false; },
20929 * Is drag and drop locked?
20931 * @return {boolean} True if drag and drop is locked, false otherwise.
20934 isLocked: function() { return this.locked; },
20937 * Location cache that is set for all drag drop objects when a drag is
20938 * initiated, cleared when the drag is finished.
20939 * @property locationCache
20946 * Set useCache to false if you want to force object the lookup of each
20947 * drag and drop linked element constantly during a drag.
20948 * @property useCache
20955 * The number of pixels that the mouse needs to move after the
20956 * mousedown before the drag is initiated. Default=3;
20957 * @property clickPixelThresh
20961 clickPixelThresh: 3,
20964 * The number of milliseconds after the mousedown event to initiate the
20965 * drag if we don't get a mouseup event. Default=1000
20966 * @property clickTimeThresh
20970 clickTimeThresh: 350,
20973 * Flag that indicates that either the drag pixel threshold or the
20974 * mousdown time threshold has been met
20975 * @property dragThreshMet
20980 dragThreshMet: false,
20983 * Timeout used for the click time threshold
20984 * @property clickTimeout
20989 clickTimeout: null,
20992 * The X position of the mousedown event stored for later use when a
20993 * drag threshold is met.
21002 * The Y position of the mousedown event stored for later use when a
21003 * drag threshold is met.
21012 * Each DragDrop instance must be registered with the DragDropMgr.
21013 * This is executed in DragDrop.init()
21014 * @method regDragDrop
21015 * @param {DragDrop} oDD the DragDrop object to register
21016 * @param {String} sGroup the name of the group this element belongs to
21019 regDragDrop: function(oDD, sGroup) {
21020 if (!this.initialized) { this.init(); }
21022 if (!this.ids[sGroup]) {
21023 this.ids[sGroup] = {};
21025 this.ids[sGroup][oDD.id] = oDD;
21029 * Removes the supplied dd instance from the supplied group. Executed
21030 * by DragDrop.removeFromGroup, so don't call this function directly.
21031 * @method removeDDFromGroup
21035 removeDDFromGroup: function(oDD, sGroup) {
21036 if (!this.ids[sGroup]) {
21037 this.ids[sGroup] = {};
21040 var obj = this.ids[sGroup];
21041 if (obj && obj[oDD.id]) {
21042 delete obj[oDD.id];
21047 * Unregisters a drag and drop item. This is executed in
21048 * DragDrop.unreg, use that method instead of calling this directly.
21053 _remove: function(oDD) {
21054 for (var g in oDD.groups) {
21055 if (g && this.ids[g][oDD.id]) {
21056 delete this.ids[g][oDD.id];
21059 delete this.handleIds[oDD.id];
21063 * Each DragDrop handle element must be registered. This is done
21064 * automatically when executing DragDrop.setHandleElId()
21065 * @method regHandle
21066 * @param {String} sDDId the DragDrop id this element is a handle for
21067 * @param {String} sHandleId the id of the element that is the drag
21071 regHandle: function(sDDId, sHandleId) {
21072 if (!this.handleIds[sDDId]) {
21073 this.handleIds[sDDId] = {};
21075 this.handleIds[sDDId][sHandleId] = sHandleId;
21079 * Utility function to determine if a given element has been
21080 * registered as a drag drop item.
21081 * @method isDragDrop
21082 * @param {String} id the element id to check
21083 * @return {boolean} true if this element is a DragDrop item,
21087 isDragDrop: function(id) {
21088 return ( this.getDDById(id) ) ? true : false;
21092 * Returns the drag and drop instances that are in all groups the
21093 * passed in instance belongs to.
21094 * @method getRelated
21095 * @param {DragDrop} p_oDD the obj to get related data for
21096 * @param {boolean} bTargetsOnly if true, only return targetable objs
21097 * @return {DragDrop[]} the related instances
21100 getRelated: function(p_oDD, bTargetsOnly) {
21102 for (var i in p_oDD.groups) {
21103 for (j in this.ids[i]) {
21104 var dd = this.ids[i][j];
21105 if (! this.isTypeOfDD(dd)) {
21108 if (!bTargetsOnly || dd.isTarget) {
21109 oDDs[oDDs.length] = dd;
21118 * Returns true if the specified dd target is a legal target for
21119 * the specifice drag obj
21120 * @method isLegalTarget
21121 * @param {DragDrop} the drag obj
21122 * @param {DragDrop} the target
21123 * @return {boolean} true if the target is a legal target for the
21127 isLegalTarget: function (oDD, oTargetDD) {
21128 var targets = this.getRelated(oDD, true);
21129 for (var i=0, len=targets.length;i<len;++i) {
21130 if (targets[i].id == oTargetDD.id) {
21139 * My goal is to be able to transparently determine if an object is
21140 * typeof DragDrop, and the exact subclass of DragDrop. typeof
21141 * returns "object", oDD.constructor.toString() always returns
21142 * "DragDrop" and not the name of the subclass. So for now it just
21143 * evaluates a well-known variable in DragDrop.
21144 * @method isTypeOfDD
21145 * @param {Object} the object to evaluate
21146 * @return {boolean} true if typeof oDD = DragDrop
21149 isTypeOfDD: function (oDD) {
21150 return (oDD && oDD.__ygDragDrop);
21154 * Utility function to determine if a given element has been
21155 * registered as a drag drop handle for the given Drag Drop object.
21157 * @param {String} id the element id to check
21158 * @return {boolean} true if this element is a DragDrop handle, false
21162 isHandle: function(sDDId, sHandleId) {
21163 return ( this.handleIds[sDDId] &&
21164 this.handleIds[sDDId][sHandleId] );
21168 * Returns the DragDrop instance for a given id
21169 * @method getDDById
21170 * @param {String} id the id of the DragDrop object
21171 * @return {DragDrop} the drag drop object, null if it is not found
21174 getDDById: function(id) {
21175 for (var i in this.ids) {
21176 if (this.ids[i][id]) {
21177 return this.ids[i][id];
21184 * Fired after a registered DragDrop object gets the mousedown event.
21185 * Sets up the events required to track the object being dragged
21186 * @method handleMouseDown
21187 * @param {Event} e the event
21188 * @param oDD the DragDrop object being dragged
21192 handleMouseDown: function(e, oDD) {
21194 Roo.QuickTips.disable();
21196 this.currentTarget = e.getTarget();
21198 this.dragCurrent = oDD;
21200 var el = oDD.getEl();
21202 // track start position
21203 this.startX = e.getPageX();
21204 this.startY = e.getPageY();
21206 this.deltaX = this.startX - el.offsetLeft;
21207 this.deltaY = this.startY - el.offsetTop;
21209 this.dragThreshMet = false;
21211 this.clickTimeout = setTimeout(
21213 var DDM = Roo.dd.DDM;
21214 DDM.startDrag(DDM.startX, DDM.startY);
21216 this.clickTimeThresh );
21220 * Fired when either the drag pixel threshol or the mousedown hold
21221 * time threshold has been met.
21222 * @method startDrag
21223 * @param x {int} the X position of the original mousedown
21224 * @param y {int} the Y position of the original mousedown
21227 startDrag: function(x, y) {
21228 clearTimeout(this.clickTimeout);
21229 if (this.dragCurrent) {
21230 this.dragCurrent.b4StartDrag(x, y);
21231 this.dragCurrent.startDrag(x, y);
21233 this.dragThreshMet = true;
21237 * Internal function to handle the mouseup event. Will be invoked
21238 * from the context of the document.
21239 * @method handleMouseUp
21240 * @param {Event} e the event
21244 handleMouseUp: function(e) {
21247 Roo.QuickTips.enable();
21249 if (! this.dragCurrent) {
21253 clearTimeout(this.clickTimeout);
21255 if (this.dragThreshMet) {
21256 this.fireEvents(e, true);
21266 * Utility to stop event propagation and event default, if these
21267 * features are turned on.
21268 * @method stopEvent
21269 * @param {Event} e the event as returned by this.getEvent()
21272 stopEvent: function(e){
21273 if(this.stopPropagation) {
21274 e.stopPropagation();
21277 if (this.preventDefault) {
21278 e.preventDefault();
21283 * Internal function to clean up event handlers after the drag
21284 * operation is complete
21286 * @param {Event} e the event
21290 stopDrag: function(e) {
21291 // Fire the drag end event for the item that was dragged
21292 if (this.dragCurrent) {
21293 if (this.dragThreshMet) {
21294 this.dragCurrent.b4EndDrag(e);
21295 this.dragCurrent.endDrag(e);
21298 this.dragCurrent.onMouseUp(e);
21301 this.dragCurrent = null;
21302 this.dragOvers = {};
21306 * Internal function to handle the mousemove event. Will be invoked
21307 * from the context of the html element.
21309 * @TODO figure out what we can do about mouse events lost when the
21310 * user drags objects beyond the window boundary. Currently we can
21311 * detect this in internet explorer by verifying that the mouse is
21312 * down during the mousemove event. Firefox doesn't give us the
21313 * button state on the mousemove event.
21314 * @method handleMouseMove
21315 * @param {Event} e the event
21319 handleMouseMove: function(e) {
21320 if (! this.dragCurrent) {
21324 // var button = e.which || e.button;
21326 // check for IE mouseup outside of page boundary
21327 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21329 return this.handleMouseUp(e);
21332 if (!this.dragThreshMet) {
21333 var diffX = Math.abs(this.startX - e.getPageX());
21334 var diffY = Math.abs(this.startY - e.getPageY());
21335 if (diffX > this.clickPixelThresh ||
21336 diffY > this.clickPixelThresh) {
21337 this.startDrag(this.startX, this.startY);
21341 if (this.dragThreshMet) {
21342 this.dragCurrent.b4Drag(e);
21343 this.dragCurrent.onDrag(e);
21344 if(!this.dragCurrent.moveOnly){
21345 this.fireEvents(e, false);
21355 * Iterates over all of the DragDrop elements to find ones we are
21356 * hovering over or dropping on
21357 * @method fireEvents
21358 * @param {Event} e the event
21359 * @param {boolean} isDrop is this a drop op or a mouseover op?
21363 fireEvents: function(e, isDrop) {
21364 var dc = this.dragCurrent;
21366 // If the user did the mouse up outside of the window, we could
21367 // get here even though we have ended the drag.
21368 if (!dc || dc.isLocked()) {
21372 var pt = e.getPoint();
21374 // cache the previous dragOver array
21380 var enterEvts = [];
21382 // Check to see if the object(s) we were hovering over is no longer
21383 // being hovered over so we can fire the onDragOut event
21384 for (var i in this.dragOvers) {
21386 var ddo = this.dragOvers[i];
21388 if (! this.isTypeOfDD(ddo)) {
21392 if (! this.isOverTarget(pt, ddo, this.mode)) {
21393 outEvts.push( ddo );
21396 oldOvers[i] = true;
21397 delete this.dragOvers[i];
21400 for (var sGroup in dc.groups) {
21402 if ("string" != typeof sGroup) {
21406 for (i in this.ids[sGroup]) {
21407 var oDD = this.ids[sGroup][i];
21408 if (! this.isTypeOfDD(oDD)) {
21412 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21413 if (this.isOverTarget(pt, oDD, this.mode)) {
21414 // look for drop interactions
21416 dropEvts.push( oDD );
21417 // look for drag enter and drag over interactions
21420 // initial drag over: dragEnter fires
21421 if (!oldOvers[oDD.id]) {
21422 enterEvts.push( oDD );
21423 // subsequent drag overs: dragOver fires
21425 overEvts.push( oDD );
21428 this.dragOvers[oDD.id] = oDD;
21436 if (outEvts.length) {
21437 dc.b4DragOut(e, outEvts);
21438 dc.onDragOut(e, outEvts);
21441 if (enterEvts.length) {
21442 dc.onDragEnter(e, enterEvts);
21445 if (overEvts.length) {
21446 dc.b4DragOver(e, overEvts);
21447 dc.onDragOver(e, overEvts);
21450 if (dropEvts.length) {
21451 dc.b4DragDrop(e, dropEvts);
21452 dc.onDragDrop(e, dropEvts);
21456 // fire dragout events
21458 for (i=0, len=outEvts.length; i<len; ++i) {
21459 dc.b4DragOut(e, outEvts[i].id);
21460 dc.onDragOut(e, outEvts[i].id);
21463 // fire enter events
21464 for (i=0,len=enterEvts.length; i<len; ++i) {
21465 // dc.b4DragEnter(e, oDD.id);
21466 dc.onDragEnter(e, enterEvts[i].id);
21469 // fire over events
21470 for (i=0,len=overEvts.length; i<len; ++i) {
21471 dc.b4DragOver(e, overEvts[i].id);
21472 dc.onDragOver(e, overEvts[i].id);
21475 // fire drop events
21476 for (i=0, len=dropEvts.length; i<len; ++i) {
21477 dc.b4DragDrop(e, dropEvts[i].id);
21478 dc.onDragDrop(e, dropEvts[i].id);
21483 // notify about a drop that did not find a target
21484 if (isDrop && !dropEvts.length) {
21485 dc.onInvalidDrop(e);
21491 * Helper function for getting the best match from the list of drag
21492 * and drop objects returned by the drag and drop events when we are
21493 * in INTERSECT mode. It returns either the first object that the
21494 * cursor is over, or the object that has the greatest overlap with
21495 * the dragged element.
21496 * @method getBestMatch
21497 * @param {DragDrop[]} dds The array of drag and drop objects
21499 * @return {DragDrop} The best single match
21502 getBestMatch: function(dds) {
21504 // Return null if the input is not what we expect
21505 //if (!dds || !dds.length || dds.length == 0) {
21507 // If there is only one item, it wins
21508 //} else if (dds.length == 1) {
21510 var len = dds.length;
21515 // Loop through the targeted items
21516 for (var i=0; i<len; ++i) {
21518 // If the cursor is over the object, it wins. If the
21519 // cursor is over multiple matches, the first one we come
21521 if (dd.cursorIsOver) {
21524 // Otherwise the object with the most overlap wins
21527 winner.overlap.getArea() < dd.overlap.getArea()) {
21538 * Refreshes the cache of the top-left and bottom-right points of the
21539 * drag and drop objects in the specified group(s). This is in the
21540 * format that is stored in the drag and drop instance, so typical
21543 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21547 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21549 * @TODO this really should be an indexed array. Alternatively this
21550 * method could accept both.
21551 * @method refreshCache
21552 * @param {Object} groups an associative array of groups to refresh
21555 refreshCache: function(groups) {
21556 for (var sGroup in groups) {
21557 if ("string" != typeof sGroup) {
21560 for (var i in this.ids[sGroup]) {
21561 var oDD = this.ids[sGroup][i];
21563 if (this.isTypeOfDD(oDD)) {
21564 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21565 var loc = this.getLocation(oDD);
21567 this.locationCache[oDD.id] = loc;
21569 delete this.locationCache[oDD.id];
21570 // this will unregister the drag and drop object if
21571 // the element is not in a usable state
21580 * This checks to make sure an element exists and is in the DOM. The
21581 * main purpose is to handle cases where innerHTML is used to remove
21582 * drag and drop objects from the DOM. IE provides an 'unspecified
21583 * error' when trying to access the offsetParent of such an element
21585 * @param {HTMLElement} el the element to check
21586 * @return {boolean} true if the element looks usable
21589 verifyEl: function(el) {
21594 parent = el.offsetParent;
21597 parent = el.offsetParent;
21608 * Returns a Region object containing the drag and drop element's position
21609 * and size, including the padding configured for it
21610 * @method getLocation
21611 * @param {DragDrop} oDD the drag and drop object to get the
21613 * @return {Roo.lib.Region} a Region object representing the total area
21614 * the element occupies, including any padding
21615 * the instance is configured for.
21618 getLocation: function(oDD) {
21619 if (! this.isTypeOfDD(oDD)) {
21623 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
21626 pos= Roo.lib.Dom.getXY(el);
21634 x2 = x1 + el.offsetWidth;
21636 y2 = y1 + el.offsetHeight;
21638 t = y1 - oDD.padding[0];
21639 r = x2 + oDD.padding[1];
21640 b = y2 + oDD.padding[2];
21641 l = x1 - oDD.padding[3];
21643 return new Roo.lib.Region( t, r, b, l );
21647 * Checks the cursor location to see if it over the target
21648 * @method isOverTarget
21649 * @param {Roo.lib.Point} pt The point to evaluate
21650 * @param {DragDrop} oTarget the DragDrop object we are inspecting
21651 * @return {boolean} true if the mouse is over the target
21655 isOverTarget: function(pt, oTarget, intersect) {
21656 // use cache if available
21657 var loc = this.locationCache[oTarget.id];
21658 if (!loc || !this.useCache) {
21659 loc = this.getLocation(oTarget);
21660 this.locationCache[oTarget.id] = loc;
21668 oTarget.cursorIsOver = loc.contains( pt );
21670 // DragDrop is using this as a sanity check for the initial mousedown
21671 // in this case we are done. In POINT mode, if the drag obj has no
21672 // contraints, we are also done. Otherwise we need to evaluate the
21673 // location of the target as related to the actual location of the
21674 // dragged element.
21675 var dc = this.dragCurrent;
21676 if (!dc || !dc.getTargetCoord ||
21677 (!intersect && !dc.constrainX && !dc.constrainY)) {
21678 return oTarget.cursorIsOver;
21681 oTarget.overlap = null;
21683 // Get the current location of the drag element, this is the
21684 // location of the mouse event less the delta that represents
21685 // where the original mousedown happened on the element. We
21686 // need to consider constraints and ticks as well.
21687 var pos = dc.getTargetCoord(pt.x, pt.y);
21689 var el = dc.getDragEl();
21690 var curRegion = new Roo.lib.Region( pos.y,
21691 pos.x + el.offsetWidth,
21692 pos.y + el.offsetHeight,
21695 var overlap = curRegion.intersect(loc);
21698 oTarget.overlap = overlap;
21699 return (intersect) ? true : oTarget.cursorIsOver;
21706 * unload event handler
21707 * @method _onUnload
21711 _onUnload: function(e, me) {
21712 Roo.dd.DragDropMgr.unregAll();
21716 * Cleans up the drag and drop events and objects.
21721 unregAll: function() {
21723 if (this.dragCurrent) {
21725 this.dragCurrent = null;
21728 this._execOnAll("unreg", []);
21730 for (i in this.elementCache) {
21731 delete this.elementCache[i];
21734 this.elementCache = {};
21739 * A cache of DOM elements
21740 * @property elementCache
21747 * Get the wrapper for the DOM element specified
21748 * @method getElWrapper
21749 * @param {String} id the id of the element to get
21750 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21752 * @deprecated This wrapper isn't that useful
21755 getElWrapper: function(id) {
21756 var oWrapper = this.elementCache[id];
21757 if (!oWrapper || !oWrapper.el) {
21758 oWrapper = this.elementCache[id] =
21759 new this.ElementWrapper(Roo.getDom(id));
21765 * Returns the actual DOM element
21766 * @method getElement
21767 * @param {String} id the id of the elment to get
21768 * @return {Object} The element
21769 * @deprecated use Roo.getDom instead
21772 getElement: function(id) {
21773 return Roo.getDom(id);
21777 * Returns the style property for the DOM element (i.e.,
21778 * document.getElById(id).style)
21780 * @param {String} id the id of the elment to get
21781 * @return {Object} The style property of the element
21782 * @deprecated use Roo.getDom instead
21785 getCss: function(id) {
21786 var el = Roo.getDom(id);
21787 return (el) ? el.style : null;
21791 * Inner class for cached elements
21792 * @class DragDropMgr.ElementWrapper
21797 ElementWrapper: function(el) {
21802 this.el = el || null;
21807 this.id = this.el && el.id;
21809 * A reference to the style property
21812 this.css = this.el && el.style;
21816 * Returns the X position of an html element
21818 * @param el the element for which to get the position
21819 * @return {int} the X coordinate
21821 * @deprecated use Roo.lib.Dom.getX instead
21824 getPosX: function(el) {
21825 return Roo.lib.Dom.getX(el);
21829 * Returns the Y position of an html element
21831 * @param el the element for which to get the position
21832 * @return {int} the Y coordinate
21833 * @deprecated use Roo.lib.Dom.getY instead
21836 getPosY: function(el) {
21837 return Roo.lib.Dom.getY(el);
21841 * Swap two nodes. In IE, we use the native method, for others we
21842 * emulate the IE behavior
21844 * @param n1 the first node to swap
21845 * @param n2 the other node to swap
21848 swapNode: function(n1, n2) {
21852 var p = n2.parentNode;
21853 var s = n2.nextSibling;
21856 p.insertBefore(n1, n2);
21857 } else if (n2 == n1.nextSibling) {
21858 p.insertBefore(n2, n1);
21860 n1.parentNode.replaceChild(n2, n1);
21861 p.insertBefore(n1, s);
21867 * Returns the current scroll position
21868 * @method getScroll
21872 getScroll: function () {
21873 var t, l, dde=document.documentElement, db=document.body;
21874 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21876 l = dde.scrollLeft;
21883 return { top: t, left: l };
21887 * Returns the specified element style property
21889 * @param {HTMLElement} el the element
21890 * @param {string} styleProp the style property
21891 * @return {string} The value of the style property
21892 * @deprecated use Roo.lib.Dom.getStyle
21895 getStyle: function(el, styleProp) {
21896 return Roo.fly(el).getStyle(styleProp);
21900 * Gets the scrollTop
21901 * @method getScrollTop
21902 * @return {int} the document's scrollTop
21905 getScrollTop: function () { return this.getScroll().top; },
21908 * Gets the scrollLeft
21909 * @method getScrollLeft
21910 * @return {int} the document's scrollTop
21913 getScrollLeft: function () { return this.getScroll().left; },
21916 * Sets the x/y position of an element to the location of the
21919 * @param {HTMLElement} moveEl The element to move
21920 * @param {HTMLElement} targetEl The position reference element
21923 moveToEl: function (moveEl, targetEl) {
21924 var aCoord = Roo.lib.Dom.getXY(targetEl);
21925 Roo.lib.Dom.setXY(moveEl, aCoord);
21929 * Numeric array sort function
21930 * @method numericSort
21933 numericSort: function(a, b) { return (a - b); },
21937 * @property _timeoutCount
21944 * Trying to make the load order less important. Without this we get
21945 * an error if this file is loaded before the Event Utility.
21946 * @method _addListeners
21950 _addListeners: function() {
21951 var DDM = Roo.dd.DDM;
21952 if ( Roo.lib.Event && document ) {
21955 if (DDM._timeoutCount > 2000) {
21957 setTimeout(DDM._addListeners, 10);
21958 if (document && document.body) {
21959 DDM._timeoutCount += 1;
21966 * Recursively searches the immediate parent and all child nodes for
21967 * the handle element in order to determine wheter or not it was
21969 * @method handleWasClicked
21970 * @param node the html element to inspect
21973 handleWasClicked: function(node, id) {
21974 if (this.isHandle(id, node.id)) {
21977 // check to see if this is a text node child of the one we want
21978 var p = node.parentNode;
21981 if (this.isHandle(id, p.id)) {
21996 // shorter alias, save a few bytes
21997 Roo.dd.DDM = Roo.dd.DragDropMgr;
21998 Roo.dd.DDM._addListeners();
22002 * Ext JS Library 1.1.1
22003 * Copyright(c) 2006-2007, Ext JS, LLC.
22005 * Originally Released Under LGPL - original licence link has changed is not relivant.
22008 * <script type="text/javascript">
22013 * A DragDrop implementation where the linked element follows the
22014 * mouse cursor during a drag.
22015 * @extends Roo.dd.DragDrop
22017 * @param {String} id the id of the linked element
22018 * @param {String} sGroup the group of related DragDrop items
22019 * @param {object} config an object containing configurable attributes
22020 * Valid properties for DD:
22023 Roo.dd.DD = function(id, sGroup, config) {
22025 this.init(id, sGroup, config);
22029 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22032 * When set to true, the utility automatically tries to scroll the browser
22033 * window wehn a drag and drop element is dragged near the viewport boundary.
22034 * Defaults to true.
22041 * Sets the pointer offset to the distance between the linked element's top
22042 * left corner and the location the element was clicked
22043 * @method autoOffset
22044 * @param {int} iPageX the X coordinate of the click
22045 * @param {int} iPageY the Y coordinate of the click
22047 autoOffset: function(iPageX, iPageY) {
22048 var x = iPageX - this.startPageX;
22049 var y = iPageY - this.startPageY;
22050 this.setDelta(x, y);
22054 * Sets the pointer offset. You can call this directly to force the
22055 * offset to be in a particular location (e.g., pass in 0,0 to set it
22056 * to the center of the object)
22058 * @param {int} iDeltaX the distance from the left
22059 * @param {int} iDeltaY the distance from the top
22061 setDelta: function(iDeltaX, iDeltaY) {
22062 this.deltaX = iDeltaX;
22063 this.deltaY = iDeltaY;
22067 * Sets the drag element to the location of the mousedown or click event,
22068 * maintaining the cursor location relative to the location on the element
22069 * that was clicked. Override this if you want to place the element in a
22070 * location other than where the cursor is.
22071 * @method setDragElPos
22072 * @param {int} iPageX the X coordinate of the mousedown or drag event
22073 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22075 setDragElPos: function(iPageX, iPageY) {
22076 // the first time we do this, we are going to check to make sure
22077 // the element has css positioning
22079 var el = this.getDragEl();
22080 this.alignElWithMouse(el, iPageX, iPageY);
22084 * Sets the element to the location of the mousedown or click event,
22085 * maintaining the cursor location relative to the location on the element
22086 * that was clicked. Override this if you want to place the element in a
22087 * location other than where the cursor is.
22088 * @method alignElWithMouse
22089 * @param {HTMLElement} el the element to move
22090 * @param {int} iPageX the X coordinate of the mousedown or drag event
22091 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22093 alignElWithMouse: function(el, iPageX, iPageY) {
22094 var oCoord = this.getTargetCoord(iPageX, iPageY);
22095 var fly = el.dom ? el : Roo.fly(el);
22096 if (!this.deltaSetXY) {
22097 var aCoord = [oCoord.x, oCoord.y];
22099 var newLeft = fly.getLeft(true);
22100 var newTop = fly.getTop(true);
22101 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22103 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22106 this.cachePosition(oCoord.x, oCoord.y);
22107 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22112 * Saves the most recent position so that we can reset the constraints and
22113 * tick marks on-demand. We need to know this so that we can calculate the
22114 * number of pixels the element is offset from its original position.
22115 * @method cachePosition
22116 * @param iPageX the current x position (optional, this just makes it so we
22117 * don't have to look it up again)
22118 * @param iPageY the current y position (optional, this just makes it so we
22119 * don't have to look it up again)
22121 cachePosition: function(iPageX, iPageY) {
22123 this.lastPageX = iPageX;
22124 this.lastPageY = iPageY;
22126 var aCoord = Roo.lib.Dom.getXY(this.getEl());
22127 this.lastPageX = aCoord[0];
22128 this.lastPageY = aCoord[1];
22133 * Auto-scroll the window if the dragged object has been moved beyond the
22134 * visible window boundary.
22135 * @method autoScroll
22136 * @param {int} x the drag element's x position
22137 * @param {int} y the drag element's y position
22138 * @param {int} h the height of the drag element
22139 * @param {int} w the width of the drag element
22142 autoScroll: function(x, y, h, w) {
22145 // The client height
22146 var clientH = Roo.lib.Dom.getViewWidth();
22148 // The client width
22149 var clientW = Roo.lib.Dom.getViewHeight();
22151 // The amt scrolled down
22152 var st = this.DDM.getScrollTop();
22154 // The amt scrolled right
22155 var sl = this.DDM.getScrollLeft();
22157 // Location of the bottom of the element
22160 // Location of the right of the element
22163 // The distance from the cursor to the bottom of the visible area,
22164 // adjusted so that we don't scroll if the cursor is beyond the
22165 // element drag constraints
22166 var toBot = (clientH + st - y - this.deltaY);
22168 // The distance from the cursor to the right of the visible area
22169 var toRight = (clientW + sl - x - this.deltaX);
22172 // How close to the edge the cursor must be before we scroll
22173 // var thresh = (document.all) ? 100 : 40;
22176 // How many pixels to scroll per autoscroll op. This helps to reduce
22177 // clunky scrolling. IE is more sensitive about this ... it needs this
22178 // value to be higher.
22179 var scrAmt = (document.all) ? 80 : 30;
22181 // Scroll down if we are near the bottom of the visible page and the
22182 // obj extends below the crease
22183 if ( bot > clientH && toBot < thresh ) {
22184 window.scrollTo(sl, st + scrAmt);
22187 // Scroll up if the window is scrolled down and the top of the object
22188 // goes above the top border
22189 if ( y < st && st > 0 && y - st < thresh ) {
22190 window.scrollTo(sl, st - scrAmt);
22193 // Scroll right if the obj is beyond the right border and the cursor is
22194 // near the border.
22195 if ( right > clientW && toRight < thresh ) {
22196 window.scrollTo(sl + scrAmt, st);
22199 // Scroll left if the window has been scrolled to the right and the obj
22200 // extends past the left border
22201 if ( x < sl && sl > 0 && x - sl < thresh ) {
22202 window.scrollTo(sl - scrAmt, st);
22208 * Finds the location the element should be placed if we want to move
22209 * it to where the mouse location less the click offset would place us.
22210 * @method getTargetCoord
22211 * @param {int} iPageX the X coordinate of the click
22212 * @param {int} iPageY the Y coordinate of the click
22213 * @return an object that contains the coordinates (Object.x and Object.y)
22216 getTargetCoord: function(iPageX, iPageY) {
22219 var x = iPageX - this.deltaX;
22220 var y = iPageY - this.deltaY;
22222 if (this.constrainX) {
22223 if (x < this.minX) { x = this.minX; }
22224 if (x > this.maxX) { x = this.maxX; }
22227 if (this.constrainY) {
22228 if (y < this.minY) { y = this.minY; }
22229 if (y > this.maxY) { y = this.maxY; }
22232 x = this.getTick(x, this.xTicks);
22233 y = this.getTick(y, this.yTicks);
22240 * Sets up config options specific to this class. Overrides
22241 * Roo.dd.DragDrop, but all versions of this method through the
22242 * inheritance chain are called
22244 applyConfig: function() {
22245 Roo.dd.DD.superclass.applyConfig.call(this);
22246 this.scroll = (this.config.scroll !== false);
22250 * Event that fires prior to the onMouseDown event. Overrides
22253 b4MouseDown: function(e) {
22254 // this.resetConstraints();
22255 this.autoOffset(e.getPageX(),
22260 * Event that fires prior to the onDrag event. Overrides
22263 b4Drag: function(e) {
22264 this.setDragElPos(e.getPageX(),
22268 toString: function() {
22269 return ("DD " + this.id);
22272 //////////////////////////////////////////////////////////////////////////
22273 // Debugging ygDragDrop events that can be overridden
22274 //////////////////////////////////////////////////////////////////////////
22276 startDrag: function(x, y) {
22279 onDrag: function(e) {
22282 onDragEnter: function(e, id) {
22285 onDragOver: function(e, id) {
22288 onDragOut: function(e, id) {
22291 onDragDrop: function(e, id) {
22294 endDrag: function(e) {
22301 * Ext JS Library 1.1.1
22302 * Copyright(c) 2006-2007, Ext JS, LLC.
22304 * Originally Released Under LGPL - original licence link has changed is not relivant.
22307 * <script type="text/javascript">
22311 * @class Roo.dd.DDProxy
22312 * A DragDrop implementation that inserts an empty, bordered div into
22313 * the document that follows the cursor during drag operations. At the time of
22314 * the click, the frame div is resized to the dimensions of the linked html
22315 * element, and moved to the exact location of the linked element.
22317 * References to the "frame" element refer to the single proxy element that
22318 * was created to be dragged in place of all DDProxy elements on the
22321 * @extends Roo.dd.DD
22323 * @param {String} id the id of the linked html element
22324 * @param {String} sGroup the group of related DragDrop objects
22325 * @param {object} config an object containing configurable attributes
22326 * Valid properties for DDProxy in addition to those in DragDrop:
22327 * resizeFrame, centerFrame, dragElId
22329 Roo.dd.DDProxy = function(id, sGroup, config) {
22331 this.init(id, sGroup, config);
22337 * The default drag frame div id
22338 * @property Roo.dd.DDProxy.dragElId
22342 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22344 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22347 * By default we resize the drag frame to be the same size as the element
22348 * we want to drag (this is to get the frame effect). We can turn it off
22349 * if we want a different behavior.
22350 * @property resizeFrame
22356 * By default the frame is positioned exactly where the drag element is, so
22357 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
22358 * you do not have constraints on the obj is to have the drag frame centered
22359 * around the cursor. Set centerFrame to true for this effect.
22360 * @property centerFrame
22363 centerFrame: false,
22366 * Creates the proxy element if it does not yet exist
22367 * @method createFrame
22369 createFrame: function() {
22371 var body = document.body;
22373 if (!body || !body.firstChild) {
22374 setTimeout( function() { self.createFrame(); }, 50 );
22378 var div = this.getDragEl();
22381 div = document.createElement("div");
22382 div.id = this.dragElId;
22385 s.position = "absolute";
22386 s.visibility = "hidden";
22388 s.border = "2px solid #aaa";
22391 // appendChild can blow up IE if invoked prior to the window load event
22392 // while rendering a table. It is possible there are other scenarios
22393 // that would cause this to happen as well.
22394 body.insertBefore(div, body.firstChild);
22399 * Initialization for the drag frame element. Must be called in the
22400 * constructor of all subclasses
22401 * @method initFrame
22403 initFrame: function() {
22404 this.createFrame();
22407 applyConfig: function() {
22408 Roo.dd.DDProxy.superclass.applyConfig.call(this);
22410 this.resizeFrame = (this.config.resizeFrame !== false);
22411 this.centerFrame = (this.config.centerFrame);
22412 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22416 * Resizes the drag frame to the dimensions of the clicked object, positions
22417 * it over the object, and finally displays it
22418 * @method showFrame
22419 * @param {int} iPageX X click position
22420 * @param {int} iPageY Y click position
22423 showFrame: function(iPageX, iPageY) {
22424 var el = this.getEl();
22425 var dragEl = this.getDragEl();
22426 var s = dragEl.style;
22428 this._resizeProxy();
22430 if (this.centerFrame) {
22431 this.setDelta( Math.round(parseInt(s.width, 10)/2),
22432 Math.round(parseInt(s.height, 10)/2) );
22435 this.setDragElPos(iPageX, iPageY);
22437 Roo.fly(dragEl).show();
22441 * The proxy is automatically resized to the dimensions of the linked
22442 * element when a drag is initiated, unless resizeFrame is set to false
22443 * @method _resizeProxy
22446 _resizeProxy: function() {
22447 if (this.resizeFrame) {
22448 var el = this.getEl();
22449 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22453 // overrides Roo.dd.DragDrop
22454 b4MouseDown: function(e) {
22455 var x = e.getPageX();
22456 var y = e.getPageY();
22457 this.autoOffset(x, y);
22458 this.setDragElPos(x, y);
22461 // overrides Roo.dd.DragDrop
22462 b4StartDrag: function(x, y) {
22463 // show the drag frame
22464 this.showFrame(x, y);
22467 // overrides Roo.dd.DragDrop
22468 b4EndDrag: function(e) {
22469 Roo.fly(this.getDragEl()).hide();
22472 // overrides Roo.dd.DragDrop
22473 // By default we try to move the element to the last location of the frame.
22474 // This is so that the default behavior mirrors that of Roo.dd.DD.
22475 endDrag: function(e) {
22477 var lel = this.getEl();
22478 var del = this.getDragEl();
22480 // Show the drag frame briefly so we can get its position
22481 del.style.visibility = "";
22484 // Hide the linked element before the move to get around a Safari
22486 lel.style.visibility = "hidden";
22487 Roo.dd.DDM.moveToEl(lel, del);
22488 del.style.visibility = "hidden";
22489 lel.style.visibility = "";
22494 beforeMove : function(){
22498 afterDrag : function(){
22502 toString: function() {
22503 return ("DDProxy " + this.id);
22509 * Ext JS Library 1.1.1
22510 * Copyright(c) 2006-2007, Ext JS, LLC.
22512 * Originally Released Under LGPL - original licence link has changed is not relivant.
22515 * <script type="text/javascript">
22519 * @class Roo.dd.DDTarget
22520 * A DragDrop implementation that does not move, but can be a drop
22521 * target. You would get the same result by simply omitting implementation
22522 * for the event callbacks, but this way we reduce the processing cost of the
22523 * event listener and the callbacks.
22524 * @extends Roo.dd.DragDrop
22526 * @param {String} id the id of the element that is a drop target
22527 * @param {String} sGroup the group of related DragDrop objects
22528 * @param {object} config an object containing configurable attributes
22529 * Valid properties for DDTarget in addition to those in
22533 Roo.dd.DDTarget = function(id, sGroup, config) {
22535 this.initTarget(id, sGroup, config);
22537 if (config && (config.listeners || config.events)) {
22538 Roo.dd.DragDrop.superclass.constructor.call(this, {
22539 listeners : config.listeners || {},
22540 events : config.events || {}
22545 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22546 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22547 toString: function() {
22548 return ("DDTarget " + this.id);
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">
22564 * @class Roo.dd.ScrollManager
22565 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22566 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22569 Roo.dd.ScrollManager = function(){
22570 var ddm = Roo.dd.DragDropMgr;
22577 var onStop = function(e){
22582 var triggerRefresh = function(){
22583 if(ddm.dragCurrent){
22584 ddm.refreshCache(ddm.dragCurrent.groups);
22588 var doScroll = function(){
22589 if(ddm.dragCurrent){
22590 var dds = Roo.dd.ScrollManager;
22592 if(proc.el.scroll(proc.dir, dds.increment)){
22596 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22601 var clearProc = function(){
22603 clearInterval(proc.id);
22610 var startProc = function(el, dir){
22611 Roo.log('scroll startproc');
22615 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
22618 var onFire = function(e, isDrop){
22620 if(isDrop || !ddm.dragCurrent){ return; }
22621 var dds = Roo.dd.ScrollManager;
22622 if(!dragEl || dragEl != ddm.dragCurrent){
22623 dragEl = ddm.dragCurrent;
22624 // refresh regions on drag start
22625 dds.refreshCache();
22628 var xy = Roo.lib.Event.getXY(e);
22629 var pt = new Roo.lib.Point(xy[0], xy[1]);
22630 for(var id in els){
22631 var el = els[id], r = el._region;
22632 if(r && r.contains(pt) && el.isScrollable()){
22633 if(r.bottom - pt.y <= dds.thresh){
22635 startProc(el, "down");
22638 }else if(r.right - pt.x <= dds.thresh){
22640 startProc(el, "left");
22643 }else if(pt.y - r.top <= dds.thresh){
22645 startProc(el, "up");
22648 }else if(pt.x - r.left <= dds.thresh){
22650 startProc(el, "right");
22659 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
22660 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
22664 * Registers new overflow element(s) to auto scroll
22665 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
22667 register : function(el){
22668 if(el instanceof Array){
22669 for(var i = 0, len = el.length; i < len; i++) {
22670 this.register(el[i]);
22676 Roo.dd.ScrollManager.els = els;
22680 * Unregisters overflow element(s) so they are no longer scrolled
22681 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
22683 unregister : function(el){
22684 if(el instanceof Array){
22685 for(var i = 0, len = el.length; i < len; i++) {
22686 this.unregister(el[i]);
22695 * The number of pixels from the edge of a container the pointer needs to be to
22696 * trigger scrolling (defaults to 25)
22702 * The number of pixels to scroll in each scroll increment (defaults to 50)
22708 * The frequency of scrolls in milliseconds (defaults to 500)
22714 * True to animate the scroll (defaults to true)
22720 * The animation duration in seconds -
22721 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22727 * Manually trigger a cache refresh.
22729 refreshCache : function(){
22730 for(var id in els){
22731 if(typeof els[id] == 'object'){ // for people extending the object prototype
22732 els[id]._region = els[id].getRegion();
22739 * Ext JS Library 1.1.1
22740 * Copyright(c) 2006-2007, Ext JS, LLC.
22742 * Originally Released Under LGPL - original licence link has changed is not relivant.
22745 * <script type="text/javascript">
22750 * @class Roo.dd.Registry
22751 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
22752 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22755 Roo.dd.Registry = function(){
22758 var autoIdSeed = 0;
22760 var getId = function(el, autogen){
22761 if(typeof el == "string"){
22765 if(!id && autogen !== false){
22766 id = "roodd-" + (++autoIdSeed);
22774 * Register a drag drop element
22775 * @param {String|HTMLElement} element The id or DOM node to register
22776 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22777 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
22778 * knows how to interpret, plus there are some specific properties known to the Registry that should be
22779 * populated in the data object (if applicable):
22781 Value Description<br />
22782 --------- ------------------------------------------<br />
22783 handles Array of DOM nodes that trigger dragging<br />
22784 for the element being registered<br />
22785 isHandle True if the element passed in triggers<br />
22786 dragging itself, else false
22789 register : function(el, data){
22791 if(typeof el == "string"){
22792 el = document.getElementById(el);
22795 elements[getId(el)] = data;
22796 if(data.isHandle !== false){
22797 handles[data.ddel.id] = data;
22800 var hs = data.handles;
22801 for(var i = 0, len = hs.length; i < len; i++){
22802 handles[getId(hs[i])] = data;
22808 * Unregister a drag drop element
22809 * @param {String|HTMLElement} element The id or DOM node to unregister
22811 unregister : function(el){
22812 var id = getId(el, false);
22813 var data = elements[id];
22815 delete elements[id];
22817 var hs = data.handles;
22818 for(var i = 0, len = hs.length; i < len; i++){
22819 delete handles[getId(hs[i], false)];
22826 * Returns the handle registered for a DOM Node by id
22827 * @param {String|HTMLElement} id The DOM node or id to look up
22828 * @return {Object} handle The custom handle data
22830 getHandle : function(id){
22831 if(typeof id != "string"){ // must be element?
22834 return handles[id];
22838 * Returns the handle that is registered for the DOM node that is the target of the event
22839 * @param {Event} e The event
22840 * @return {Object} handle The custom handle data
22842 getHandleFromEvent : function(e){
22843 var t = Roo.lib.Event.getTarget(e);
22844 return t ? handles[t.id] : null;
22848 * Returns a custom data object that is registered for a DOM node by id
22849 * @param {String|HTMLElement} id The DOM node or id to look up
22850 * @return {Object} data The custom data
22852 getTarget : function(id){
22853 if(typeof id != "string"){ // must be element?
22856 return elements[id];
22860 * Returns a custom data object that is registered for the DOM node that is the target of the event
22861 * @param {Event} e The event
22862 * @return {Object} data The custom data
22864 getTargetFromEvent : function(e){
22865 var t = Roo.lib.Event.getTarget(e);
22866 return t ? elements[t.id] || handles[t.id] : null;
22871 * Ext JS Library 1.1.1
22872 * Copyright(c) 2006-2007, Ext JS, LLC.
22874 * Originally Released Under LGPL - original licence link has changed is not relivant.
22877 * <script type="text/javascript">
22882 * @class Roo.dd.StatusProxy
22883 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22884 * default drag proxy used by all Roo.dd components.
22886 * @param {Object} config
22888 Roo.dd.StatusProxy = function(config){
22889 Roo.apply(this, config);
22890 this.id = this.id || Roo.id();
22891 this.el = new Roo.Layer({
22893 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22894 {tag: "div", cls: "x-dd-drop-icon"},
22895 {tag: "div", cls: "x-dd-drag-ghost"}
22898 shadow: !config || config.shadow !== false
22900 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22901 this.dropStatus = this.dropNotAllowed;
22904 Roo.dd.StatusProxy.prototype = {
22906 * @cfg {String} dropAllowed
22907 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22909 dropAllowed : "x-dd-drop-ok",
22911 * @cfg {String} dropNotAllowed
22912 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22914 dropNotAllowed : "x-dd-drop-nodrop",
22917 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22918 * over the current target element.
22919 * @param {String} cssClass The css class for the new drop status indicator image
22921 setStatus : function(cssClass){
22922 cssClass = cssClass || this.dropNotAllowed;
22923 if(this.dropStatus != cssClass){
22924 this.el.replaceClass(this.dropStatus, cssClass);
22925 this.dropStatus = cssClass;
22930 * Resets the status indicator to the default dropNotAllowed value
22931 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22933 reset : function(clearGhost){
22934 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22935 this.dropStatus = this.dropNotAllowed;
22937 this.ghost.update("");
22942 * Updates the contents of the ghost element
22943 * @param {String} html The html that will replace the current innerHTML of the ghost element
22945 update : function(html){
22946 if(typeof html == "string"){
22947 this.ghost.update(html);
22949 this.ghost.update("");
22950 html.style.margin = "0";
22951 this.ghost.dom.appendChild(html);
22953 // ensure float = none set?? cant remember why though.
22954 var el = this.ghost.dom.firstChild;
22956 Roo.fly(el).setStyle('float', 'none');
22961 * Returns the underlying proxy {@link Roo.Layer}
22962 * @return {Roo.Layer} el
22964 getEl : function(){
22969 * Returns the ghost element
22970 * @return {Roo.Element} el
22972 getGhost : function(){
22978 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22980 hide : function(clear){
22988 * Stops the repair animation if it's currently running
22991 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22997 * Displays this proxy
23004 * Force the Layer to sync its shadow and shim positions to the element
23011 * Causes the proxy to return to its position of origin via an animation. Should be called after an
23012 * invalid drop operation by the item being dragged.
23013 * @param {Array} xy The XY position of the element ([x, y])
23014 * @param {Function} callback The function to call after the repair is complete
23015 * @param {Object} scope The scope in which to execute the callback
23017 repair : function(xy, callback, scope){
23018 this.callback = callback;
23019 this.scope = scope;
23020 if(xy && this.animRepair !== false){
23021 this.el.addClass("x-dd-drag-repair");
23022 this.el.hideUnders(true);
23023 this.anim = this.el.shift({
23024 duration: this.repairDuration || .5,
23028 callback: this.afterRepair,
23032 this.afterRepair();
23037 afterRepair : function(){
23039 if(typeof this.callback == "function"){
23040 this.callback.call(this.scope || this);
23042 this.callback = null;
23047 * Ext JS Library 1.1.1
23048 * Copyright(c) 2006-2007, Ext JS, LLC.
23050 * Originally Released Under LGPL - original licence link has changed is not relivant.
23053 * <script type="text/javascript">
23057 * @class Roo.dd.DragSource
23058 * @extends Roo.dd.DDProxy
23059 * A simple class that provides the basic implementation needed to make any element draggable.
23061 * @param {String/HTMLElement/Element} el The container element
23062 * @param {Object} config
23064 Roo.dd.DragSource = function(el, config){
23065 this.el = Roo.get(el);
23066 this.dragData = {};
23068 Roo.apply(this, config);
23071 this.proxy = new Roo.dd.StatusProxy();
23074 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23075 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23077 this.dragging = false;
23080 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23082 * @cfg {String} dropAllowed
23083 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23085 dropAllowed : "x-dd-drop-ok",
23087 * @cfg {String} dropNotAllowed
23088 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23090 dropNotAllowed : "x-dd-drop-nodrop",
23093 * Returns the data object associated with this drag source
23094 * @return {Object} data An object containing arbitrary data
23096 getDragData : function(e){
23097 return this.dragData;
23101 onDragEnter : function(e, id){
23102 var target = Roo.dd.DragDropMgr.getDDById(id);
23103 this.cachedTarget = target;
23104 if(this.beforeDragEnter(target, e, id) !== false){
23105 if(target.isNotifyTarget){
23106 var status = target.notifyEnter(this, e, this.dragData);
23107 this.proxy.setStatus(status);
23109 this.proxy.setStatus(this.dropAllowed);
23112 if(this.afterDragEnter){
23114 * An empty function by default, but provided so that you can perform a custom action
23115 * when the dragged item enters the drop target by providing an implementation.
23116 * @param {Roo.dd.DragDrop} target The drop target
23117 * @param {Event} e The event object
23118 * @param {String} id The id of the dragged element
23119 * @method afterDragEnter
23121 this.afterDragEnter(target, e, id);
23127 * An empty function by default, but provided so that you can perform a custom action
23128 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23129 * @param {Roo.dd.DragDrop} target The drop target
23130 * @param {Event} e The event object
23131 * @param {String} id The id of the dragged element
23132 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23134 beforeDragEnter : function(target, e, id){
23139 alignElWithMouse: function() {
23140 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23145 onDragOver : function(e, id){
23146 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23147 if(this.beforeDragOver(target, e, id) !== false){
23148 if(target.isNotifyTarget){
23149 var status = target.notifyOver(this, e, this.dragData);
23150 this.proxy.setStatus(status);
23153 if(this.afterDragOver){
23155 * An empty function by default, but provided so that you can perform a custom action
23156 * while the dragged item is over the drop target by providing an implementation.
23157 * @param {Roo.dd.DragDrop} target The drop target
23158 * @param {Event} e The event object
23159 * @param {String} id The id of the dragged element
23160 * @method afterDragOver
23162 this.afterDragOver(target, e, id);
23168 * An empty function by default, but provided so that you can perform a custom action
23169 * while the dragged item is over the drop target and optionally cancel the onDragOver.
23170 * @param {Roo.dd.DragDrop} target The drop target
23171 * @param {Event} e The event object
23172 * @param {String} id The id of the dragged element
23173 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23175 beforeDragOver : function(target, e, id){
23180 onDragOut : function(e, id){
23181 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23182 if(this.beforeDragOut(target, e, id) !== false){
23183 if(target.isNotifyTarget){
23184 target.notifyOut(this, e, this.dragData);
23186 this.proxy.reset();
23187 if(this.afterDragOut){
23189 * An empty function by default, but provided so that you can perform a custom action
23190 * after the dragged item is dragged out of the target without dropping.
23191 * @param {Roo.dd.DragDrop} target The drop target
23192 * @param {Event} e The event object
23193 * @param {String} id The id of the dragged element
23194 * @method afterDragOut
23196 this.afterDragOut(target, e, id);
23199 this.cachedTarget = null;
23203 * An empty function by default, but provided so that you can perform a custom action before the dragged
23204 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23205 * @param {Roo.dd.DragDrop} target The drop target
23206 * @param {Event} e The event object
23207 * @param {String} id The id of the dragged element
23208 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23210 beforeDragOut : function(target, e, id){
23215 onDragDrop : function(e, id){
23216 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23217 if(this.beforeDragDrop(target, e, id) !== false){
23218 if(target.isNotifyTarget){
23219 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23220 this.onValidDrop(target, e, id);
23222 this.onInvalidDrop(target, e, id);
23225 this.onValidDrop(target, e, id);
23228 if(this.afterDragDrop){
23230 * An empty function by default, but provided so that you can perform a custom action
23231 * after a valid drag drop has occurred by providing an implementation.
23232 * @param {Roo.dd.DragDrop} target The drop target
23233 * @param {Event} e The event object
23234 * @param {String} id The id of the dropped element
23235 * @method afterDragDrop
23237 this.afterDragDrop(target, e, id);
23240 delete this.cachedTarget;
23244 * An empty function by default, but provided so that you can perform a custom action before the dragged
23245 * item is dropped onto the target and optionally cancel the onDragDrop.
23246 * @param {Roo.dd.DragDrop} target The drop target
23247 * @param {Event} e The event object
23248 * @param {String} id The id of the dragged element
23249 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23251 beforeDragDrop : function(target, e, id){
23256 onValidDrop : function(target, e, id){
23258 if(this.afterValidDrop){
23260 * An empty function by default, but provided so that you can perform a custom action
23261 * after a valid drop has occurred by providing an implementation.
23262 * @param {Object} target The target DD
23263 * @param {Event} e The event object
23264 * @param {String} id The id of the dropped element
23265 * @method afterInvalidDrop
23267 this.afterValidDrop(target, e, id);
23272 getRepairXY : function(e, data){
23273 return this.el.getXY();
23277 onInvalidDrop : function(target, e, id){
23278 this.beforeInvalidDrop(target, e, id);
23279 if(this.cachedTarget){
23280 if(this.cachedTarget.isNotifyTarget){
23281 this.cachedTarget.notifyOut(this, e, this.dragData);
23283 this.cacheTarget = null;
23285 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23287 if(this.afterInvalidDrop){
23289 * An empty function by default, but provided so that you can perform a custom action
23290 * after an invalid drop has occurred by providing an implementation.
23291 * @param {Event} e The event object
23292 * @param {String} id The id of the dropped element
23293 * @method afterInvalidDrop
23295 this.afterInvalidDrop(e, id);
23300 afterRepair : function(){
23302 this.el.highlight(this.hlColor || "c3daf9");
23304 this.dragging = false;
23308 * An empty function by default, but provided so that you can perform a custom action after an invalid
23309 * drop has occurred.
23310 * @param {Roo.dd.DragDrop} target The drop target
23311 * @param {Event} e The event object
23312 * @param {String} id The id of the dragged element
23313 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23315 beforeInvalidDrop : function(target, e, id){
23320 handleMouseDown : function(e){
23321 if(this.dragging) {
23324 var data = this.getDragData(e);
23325 if(data && this.onBeforeDrag(data, e) !== false){
23326 this.dragData = data;
23328 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23333 * An empty function by default, but provided so that you can perform a custom action before the initial
23334 * drag event begins and optionally cancel it.
23335 * @param {Object} data An object containing arbitrary data to be shared with drop targets
23336 * @param {Event} e The event object
23337 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23339 onBeforeDrag : function(data, e){
23344 * An empty function by default, but provided so that you can perform a custom action once the initial
23345 * drag event has begun. The drag cannot be canceled from this function.
23346 * @param {Number} x The x position of the click on the dragged object
23347 * @param {Number} y The y position of the click on the dragged object
23349 onStartDrag : Roo.emptyFn,
23351 // private - YUI override
23352 startDrag : function(x, y){
23353 this.proxy.reset();
23354 this.dragging = true;
23355 this.proxy.update("");
23356 this.onInitDrag(x, y);
23361 onInitDrag : function(x, y){
23362 var clone = this.el.dom.cloneNode(true);
23363 clone.id = Roo.id(); // prevent duplicate ids
23364 this.proxy.update(clone);
23365 this.onStartDrag(x, y);
23370 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23371 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23373 getProxy : function(){
23378 * Hides the drag source's {@link Roo.dd.StatusProxy}
23380 hideProxy : function(){
23382 this.proxy.reset(true);
23383 this.dragging = false;
23387 triggerCacheRefresh : function(){
23388 Roo.dd.DDM.refreshCache(this.groups);
23391 // private - override to prevent hiding
23392 b4EndDrag: function(e) {
23395 // private - override to prevent moving
23396 endDrag : function(e){
23397 this.onEndDrag(this.dragData, e);
23401 onEndDrag : function(data, e){
23404 // private - pin to cursor
23405 autoOffset : function(x, y) {
23406 this.setDelta(-12, -20);
23410 * Ext JS Library 1.1.1
23411 * Copyright(c) 2006-2007, Ext JS, LLC.
23413 * Originally Released Under LGPL - original licence link has changed is not relivant.
23416 * <script type="text/javascript">
23421 * @class Roo.dd.DropTarget
23422 * @extends Roo.dd.DDTarget
23423 * A simple class that provides the basic implementation needed to make any element a drop target that can have
23424 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
23426 * @param {String/HTMLElement/Element} el The container element
23427 * @param {Object} config
23429 Roo.dd.DropTarget = function(el, config){
23430 this.el = Roo.get(el);
23432 var listeners = false; ;
23433 if (config && config.listeners) {
23434 listeners= config.listeners;
23435 delete config.listeners;
23437 Roo.apply(this, config);
23439 if(this.containerScroll){
23440 Roo.dd.ScrollManager.register(this.el);
23444 * @scope Roo.dd.DropTarget
23449 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23450 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
23451 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
23453 * IMPORTANT : it should set this.valid to true|false
23455 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23456 * @param {Event} e The event
23457 * @param {Object} data An object containing arbitrary data supplied by the drag source
23463 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23464 * This method will be called on every mouse movement while the drag source is over the drop target.
23465 * This default implementation simply returns the dropAllowed config value.
23467 * IMPORTANT : it should set this.valid to true|false
23469 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23470 * @param {Event} e The event
23471 * @param {Object} data An object containing arbitrary data supplied by the drag source
23477 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23478 * out of the target without dropping. This default implementation simply removes the CSS class specified by
23479 * overClass (if any) from the drop element.
23482 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23483 * @param {Event} e The event
23484 * @param {Object} data An object containing arbitrary data supplied by the drag source
23490 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23491 * been dropped on it. This method has no default implementation and returns false, so you must provide an
23492 * implementation that does something to process the drop event and returns true so that the drag source's
23493 * repair action does not run.
23495 * IMPORTANT : it should set this.success
23497 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23498 * @param {Event} e The event
23499 * @param {Object} data An object containing arbitrary data supplied by the drag source
23505 Roo.dd.DropTarget.superclass.constructor.call( this,
23507 this.ddGroup || this.group,
23510 listeners : listeners || {}
23518 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23520 * @cfg {String} overClass
23521 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23524 * @cfg {String} ddGroup
23525 * The drag drop group to handle drop events for
23529 * @cfg {String} dropAllowed
23530 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23532 dropAllowed : "x-dd-drop-ok",
23534 * @cfg {String} dropNotAllowed
23535 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23537 dropNotAllowed : "x-dd-drop-nodrop",
23539 * @cfg {boolean} success
23540 * set this after drop listener..
23544 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23545 * if the drop point is valid for over/enter..
23552 isNotifyTarget : true,
23557 notifyEnter : function(dd, e, data)
23560 this.fireEvent('enter', dd, e, data);
23561 if(this.overClass){
23562 this.el.addClass(this.overClass);
23564 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23565 this.valid ? this.dropAllowed : this.dropNotAllowed
23572 notifyOver : function(dd, e, data)
23575 this.fireEvent('over', dd, e, data);
23576 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23577 this.valid ? this.dropAllowed : this.dropNotAllowed
23584 notifyOut : function(dd, e, data)
23586 this.fireEvent('out', dd, e, data);
23587 if(this.overClass){
23588 this.el.removeClass(this.overClass);
23595 notifyDrop : function(dd, e, data)
23597 this.success = false;
23598 this.fireEvent('drop', dd, e, data);
23599 return this.success;
23603 * Ext JS Library 1.1.1
23604 * Copyright(c) 2006-2007, Ext JS, LLC.
23606 * Originally Released Under LGPL - original licence link has changed is not relivant.
23609 * <script type="text/javascript">
23614 * @class Roo.dd.DragZone
23615 * @extends Roo.dd.DragSource
23616 * This class provides a container DD instance that proxies for multiple child node sources.<br />
23617 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
23619 * @param {String/HTMLElement/Element} el The container element
23620 * @param {Object} config
23622 Roo.dd.DragZone = function(el, config){
23623 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
23624 if(this.containerScroll){
23625 Roo.dd.ScrollManager.register(this.el);
23629 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
23631 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
23632 * for auto scrolling during drag operations.
23635 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
23636 * method after a failed drop (defaults to "c3daf9" - light blue)
23640 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
23641 * for a valid target to drag based on the mouse down. Override this method
23642 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
23643 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
23644 * @param {EventObject} e The mouse down event
23645 * @return {Object} The dragData
23647 getDragData : function(e){
23648 return Roo.dd.Registry.getHandleFromEvent(e);
23652 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
23653 * this.dragData.ddel
23654 * @param {Number} x The x position of the click on the dragged object
23655 * @param {Number} y The y position of the click on the dragged object
23656 * @return {Boolean} true to continue the drag, false to cancel
23658 onInitDrag : function(x, y){
23659 this.proxy.update(this.dragData.ddel.cloneNode(true));
23660 this.onStartDrag(x, y);
23665 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
23667 afterRepair : function(){
23669 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
23671 this.dragging = false;
23675 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
23676 * the XY of this.dragData.ddel
23677 * @param {EventObject} e The mouse up event
23678 * @return {Array} The xy location (e.g. [100, 200])
23680 getRepairXY : function(e){
23681 return Roo.Element.fly(this.dragData.ddel).getXY();
23685 * Ext JS Library 1.1.1
23686 * Copyright(c) 2006-2007, Ext JS, LLC.
23688 * Originally Released Under LGPL - original licence link has changed is not relivant.
23691 * <script type="text/javascript">
23694 * @class Roo.dd.DropZone
23695 * @extends Roo.dd.DropTarget
23696 * This class provides a container DD instance that proxies for multiple child node targets.<br />
23697 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
23699 * @param {String/HTMLElement/Element} el The container element
23700 * @param {Object} config
23702 Roo.dd.DropZone = function(el, config){
23703 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
23706 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
23708 * Returns a custom data object associated with the DOM node that is the target of the event. By default
23709 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
23710 * provide your own custom lookup.
23711 * @param {Event} e The event
23712 * @return {Object} data The custom data
23714 getTargetFromEvent : function(e){
23715 return Roo.dd.Registry.getTargetFromEvent(e);
23719 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
23720 * that it has registered. This method has no default implementation and should be overridden to provide
23721 * node-specific processing if necessary.
23722 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23723 * {@link #getTargetFromEvent} for this node)
23724 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23725 * @param {Event} e The event
23726 * @param {Object} data An object containing arbitrary data supplied by the drag source
23728 onNodeEnter : function(n, dd, e, data){
23733 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23734 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
23735 * overridden to provide the proper feedback.
23736 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23737 * {@link #getTargetFromEvent} for this node)
23738 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23739 * @param {Event} e The event
23740 * @param {Object} data An object containing arbitrary data supplied by the drag source
23741 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23742 * underlying {@link Roo.dd.StatusProxy} can be updated
23744 onNodeOver : function(n, dd, e, data){
23745 return this.dropAllowed;
23749 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23750 * the drop node without dropping. This method has no default implementation and should be overridden to provide
23751 * node-specific processing if necessary.
23752 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23753 * {@link #getTargetFromEvent} for this node)
23754 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23755 * @param {Event} e The event
23756 * @param {Object} data An object containing arbitrary data supplied by the drag source
23758 onNodeOut : function(n, dd, e, data){
23763 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23764 * the drop node. The default implementation returns false, so it should be overridden to provide the
23765 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23766 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23767 * {@link #getTargetFromEvent} for this node)
23768 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23769 * @param {Event} e The event
23770 * @param {Object} data An object containing arbitrary data supplied by the drag source
23771 * @return {Boolean} True if the drop was valid, else false
23773 onNodeDrop : function(n, dd, e, data){
23778 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23779 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
23780 * it should be overridden to provide the proper feedback if necessary.
23781 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23782 * @param {Event} e The event
23783 * @param {Object} data An object containing arbitrary data supplied by the drag source
23784 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23785 * underlying {@link Roo.dd.StatusProxy} can be updated
23787 onContainerOver : function(dd, e, data){
23788 return this.dropNotAllowed;
23792 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23793 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
23794 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23795 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
23796 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23797 * @param {Event} e The event
23798 * @param {Object} data An object containing arbitrary data supplied by the drag source
23799 * @return {Boolean} True if the drop was valid, else false
23801 onContainerDrop : function(dd, e, data){
23806 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23807 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
23808 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23809 * you should override this method and provide a custom implementation.
23810 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23811 * @param {Event} e The event
23812 * @param {Object} data An object containing arbitrary data supplied by the drag source
23813 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23814 * underlying {@link Roo.dd.StatusProxy} can be updated
23816 notifyEnter : function(dd, e, data){
23817 return this.dropNotAllowed;
23821 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23822 * This method will be called on every mouse movement while the drag source is over the drop zone.
23823 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23824 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23825 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23826 * registered node, it will call {@link #onContainerOver}.
23827 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23828 * @param {Event} e The event
23829 * @param {Object} data An object containing arbitrary data supplied by the drag source
23830 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23831 * underlying {@link Roo.dd.StatusProxy} can be updated
23833 notifyOver : function(dd, e, data){
23834 var n = this.getTargetFromEvent(e);
23835 if(!n){ // not over valid drop target
23836 if(this.lastOverNode){
23837 this.onNodeOut(this.lastOverNode, dd, e, data);
23838 this.lastOverNode = null;
23840 return this.onContainerOver(dd, e, data);
23842 if(this.lastOverNode != n){
23843 if(this.lastOverNode){
23844 this.onNodeOut(this.lastOverNode, dd, e, data);
23846 this.onNodeEnter(n, dd, e, data);
23847 this.lastOverNode = n;
23849 return this.onNodeOver(n, dd, e, data);
23853 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23854 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23855 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23856 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23857 * @param {Event} e The event
23858 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23860 notifyOut : function(dd, e, data){
23861 if(this.lastOverNode){
23862 this.onNodeOut(this.lastOverNode, dd, e, data);
23863 this.lastOverNode = null;
23868 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23869 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23870 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23871 * otherwise it will call {@link #onContainerDrop}.
23872 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23873 * @param {Event} e The event
23874 * @param {Object} data An object containing arbitrary data supplied by the drag source
23875 * @return {Boolean} True if the drop was valid, else false
23877 notifyDrop : function(dd, e, data){
23878 if(this.lastOverNode){
23879 this.onNodeOut(this.lastOverNode, dd, e, data);
23880 this.lastOverNode = null;
23882 var n = this.getTargetFromEvent(e);
23884 this.onNodeDrop(n, dd, e, data) :
23885 this.onContainerDrop(dd, e, data);
23889 triggerCacheRefresh : function(){
23890 Roo.dd.DDM.refreshCache(this.groups);
23894 * Ext JS Library 1.1.1
23895 * Copyright(c) 2006-2007, Ext JS, LLC.
23897 * Originally Released Under LGPL - original licence link has changed is not relivant.
23900 * <script type="text/javascript">
23905 * @class Roo.data.SortTypes
23907 * Defines the default sorting (casting?) comparison functions used when sorting data.
23909 Roo.data.SortTypes = {
23911 * Default sort that does nothing
23912 * @param {Mixed} s The value being converted
23913 * @return {Mixed} The comparison value
23915 none : function(s){
23920 * The regular expression used to strip tags
23924 stripTagsRE : /<\/?[^>]+>/gi,
23927 * Strips all HTML tags to sort on text only
23928 * @param {Mixed} s The value being converted
23929 * @return {String} The comparison value
23931 asText : function(s){
23932 return String(s).replace(this.stripTagsRE, "");
23936 * Strips all HTML tags to sort on text only - Case insensitive
23937 * @param {Mixed} s The value being converted
23938 * @return {String} The comparison value
23940 asUCText : function(s){
23941 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23945 * Case insensitive string
23946 * @param {Mixed} s The value being converted
23947 * @return {String} The comparison value
23949 asUCString : function(s) {
23950 return String(s).toUpperCase();
23955 * @param {Mixed} s The value being converted
23956 * @return {Number} The comparison value
23958 asDate : function(s) {
23962 if(s instanceof Date){
23963 return s.getTime();
23965 return Date.parse(String(s));
23970 * @param {Mixed} s The value being converted
23971 * @return {Float} The comparison value
23973 asFloat : function(s) {
23974 var val = parseFloat(String(s).replace(/,/g, ""));
23983 * @param {Mixed} s The value being converted
23984 * @return {Number} The comparison value
23986 asInt : function(s) {
23987 var val = parseInt(String(s).replace(/,/g, ""));
23995 * Ext JS Library 1.1.1
23996 * Copyright(c) 2006-2007, Ext JS, LLC.
23998 * Originally Released Under LGPL - original licence link has changed is not relivant.
24001 * <script type="text/javascript">
24005 * @class Roo.data.Record
24006 * Instances of this class encapsulate both record <em>definition</em> information, and record
24007 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
24008 * to access Records cached in an {@link Roo.data.Store} object.<br>
24010 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
24011 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
24014 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
24016 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
24017 * {@link #create}. The parameters are the same.
24018 * @param {Array} data An associative Array of data values keyed by the field name.
24019 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
24020 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
24021 * not specified an integer id is generated.
24023 Roo.data.Record = function(data, id){
24024 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
24029 * Generate a constructor for a specific record layout.
24030 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
24031 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
24032 * Each field definition object may contain the following properties: <ul>
24033 * <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,
24034 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
24035 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
24036 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
24037 * is being used, then this is a string containing the javascript expression to reference the data relative to
24038 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
24039 * to the data item relative to the record element. If the mapping expression is the same as the field name,
24040 * this may be omitted.</p></li>
24041 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
24042 * <ul><li>auto (Default, implies no conversion)</li>
24047 * <li>date</li></ul></p></li>
24048 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
24049 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
24050 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
24051 * by the Reader into an object that will be stored in the Record. It is passed the
24052 * following parameters:<ul>
24053 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
24055 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
24057 * <br>usage:<br><pre><code>
24058 var TopicRecord = Roo.data.Record.create(
24059 {name: 'title', mapping: 'topic_title'},
24060 {name: 'author', mapping: 'username'},
24061 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
24062 {name: 'lastPost', mapping: 'post_time', type: 'date'},
24063 {name: 'lastPoster', mapping: 'user2'},
24064 {name: 'excerpt', mapping: 'post_text'}
24067 var myNewRecord = new TopicRecord({
24068 title: 'Do my job please',
24071 lastPost: new Date(),
24072 lastPoster: 'Animal',
24073 excerpt: 'No way dude!'
24075 myStore.add(myNewRecord);
24080 Roo.data.Record.create = function(o){
24081 var f = function(){
24082 f.superclass.constructor.apply(this, arguments);
24084 Roo.extend(f, Roo.data.Record);
24085 var p = f.prototype;
24086 p.fields = new Roo.util.MixedCollection(false, function(field){
24089 for(var i = 0, len = o.length; i < len; i++){
24090 p.fields.add(new Roo.data.Field(o[i]));
24092 f.getField = function(name){
24093 return p.fields.get(name);
24098 Roo.data.Record.AUTO_ID = 1000;
24099 Roo.data.Record.EDIT = 'edit';
24100 Roo.data.Record.REJECT = 'reject';
24101 Roo.data.Record.COMMIT = 'commit';
24103 Roo.data.Record.prototype = {
24105 * Readonly flag - true if this record has been modified.
24114 join : function(store){
24115 this.store = store;
24119 * Set the named field to the specified value.
24120 * @param {String} name The name of the field to set.
24121 * @param {Object} value The value to set the field to.
24123 set : function(name, value){
24124 if(this.data[name] == value){
24128 if(!this.modified){
24129 this.modified = {};
24131 if(typeof this.modified[name] == 'undefined'){
24132 this.modified[name] = this.data[name];
24134 this.data[name] = value;
24135 if(!this.editing && this.store){
24136 this.store.afterEdit(this);
24141 * Get the value of the named field.
24142 * @param {String} name The name of the field to get the value of.
24143 * @return {Object} The value of the field.
24145 get : function(name){
24146 return this.data[name];
24150 beginEdit : function(){
24151 this.editing = true;
24152 this.modified = {};
24156 cancelEdit : function(){
24157 this.editing = false;
24158 delete this.modified;
24162 endEdit : function(){
24163 this.editing = false;
24164 if(this.dirty && this.store){
24165 this.store.afterEdit(this);
24170 * Usually called by the {@link Roo.data.Store} which owns the Record.
24171 * Rejects all changes made to the Record since either creation, or the last commit operation.
24172 * Modified fields are reverted to their original values.
24174 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
24175 * of reject operations.
24177 reject : function(){
24178 var m = this.modified;
24180 if(typeof m[n] != "function"){
24181 this.data[n] = m[n];
24184 this.dirty = false;
24185 delete this.modified;
24186 this.editing = false;
24188 this.store.afterReject(this);
24193 * Usually called by the {@link Roo.data.Store} which owns the Record.
24194 * Commits all changes made to the Record since either creation, or the last commit operation.
24196 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
24197 * of commit operations.
24199 commit : function(){
24200 this.dirty = false;
24201 delete this.modified;
24202 this.editing = false;
24204 this.store.afterCommit(this);
24209 hasError : function(){
24210 return this.error != null;
24214 clearError : function(){
24219 * Creates a copy of this record.
24220 * @param {String} id (optional) A new record id if you don't want to use this record's id
24223 copy : function(newId) {
24224 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
24228 * Ext JS Library 1.1.1
24229 * Copyright(c) 2006-2007, Ext JS, LLC.
24231 * Originally Released Under LGPL - original licence link has changed is not relivant.
24234 * <script type="text/javascript">
24240 * @class Roo.data.Store
24241 * @extends Roo.util.Observable
24242 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
24243 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
24245 * 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
24246 * has no knowledge of the format of the data returned by the Proxy.<br>
24248 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
24249 * instances from the data object. These records are cached and made available through accessor functions.
24251 * Creates a new Store.
24252 * @param {Object} config A config object containing the objects needed for the Store to access data,
24253 * and read the data into Records.
24255 Roo.data.Store = function(config){
24256 this.data = new Roo.util.MixedCollection(false);
24257 this.data.getKey = function(o){
24260 this.baseParams = {};
24262 this.paramNames = {
24267 "multisort" : "_multisort"
24270 if(config && config.data){
24271 this.inlineData = config.data;
24272 delete config.data;
24275 Roo.apply(this, config);
24277 if(this.reader){ // reader passed
24278 this.reader = Roo.factory(this.reader, Roo.data);
24279 this.reader.xmodule = this.xmodule || false;
24280 if(!this.recordType){
24281 this.recordType = this.reader.recordType;
24283 if(this.reader.onMetaChange){
24284 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
24288 if(this.recordType){
24289 this.fields = this.recordType.prototype.fields;
24291 this.modified = [];
24295 * @event datachanged
24296 * Fires when the data cache has changed, and a widget which is using this Store
24297 * as a Record cache should refresh its view.
24298 * @param {Store} this
24300 datachanged : true,
24302 * @event metachange
24303 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
24304 * @param {Store} this
24305 * @param {Object} meta The JSON metadata
24310 * Fires when Records have been added to the Store
24311 * @param {Store} this
24312 * @param {Roo.data.Record[]} records The array of Records added
24313 * @param {Number} index The index at which the record(s) were added
24318 * Fires when a Record has been removed from the Store
24319 * @param {Store} this
24320 * @param {Roo.data.Record} record The Record that was removed
24321 * @param {Number} index The index at which the record was removed
24326 * Fires when a Record has been updated
24327 * @param {Store} this
24328 * @param {Roo.data.Record} record The Record that was updated
24329 * @param {String} operation The update operation being performed. Value may be one of:
24331 Roo.data.Record.EDIT
24332 Roo.data.Record.REJECT
24333 Roo.data.Record.COMMIT
24339 * Fires when the data cache has been cleared.
24340 * @param {Store} this
24344 * @event beforeload
24345 * Fires before a request is made for a new data object. If the beforeload handler returns false
24346 * the load action will be canceled.
24347 * @param {Store} this
24348 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24352 * @event beforeloadadd
24353 * Fires after a new set of Records has been loaded.
24354 * @param {Store} this
24355 * @param {Roo.data.Record[]} records The Records that were loaded
24356 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24358 beforeloadadd : true,
24361 * Fires after a new set of Records has been loaded, before they are added to the store.
24362 * @param {Store} this
24363 * @param {Roo.data.Record[]} records The Records that were loaded
24364 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24365 * @params {Object} return from reader
24369 * @event loadexception
24370 * Fires if an exception occurs in the Proxy during loading.
24371 * Called with the signature of the Proxy's "loadexception" event.
24372 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
24375 * @param {Object} return from JsonData.reader() - success, totalRecords, records
24376 * @param {Object} load options
24377 * @param {Object} jsonData from your request (normally this contains the Exception)
24379 loadexception : true
24383 this.proxy = Roo.factory(this.proxy, Roo.data);
24384 this.proxy.xmodule = this.xmodule || false;
24385 this.relayEvents(this.proxy, ["loadexception"]);
24387 this.sortToggle = {};
24388 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
24390 Roo.data.Store.superclass.constructor.call(this);
24392 if(this.inlineData){
24393 this.loadData(this.inlineData);
24394 delete this.inlineData;
24398 Roo.extend(Roo.data.Store, Roo.util.Observable, {
24400 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
24401 * without a remote query - used by combo/forms at present.
24405 * @cfg {Roo.data.DataProxy} proxy [required] The Proxy object which provides access to a data object.
24408 * @cfg {Array} data Inline data to be loaded when the store is initialized.
24411 * @cfg {Roo.data.DataReader} reader [required] The Reader object which processes the data object and returns
24412 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
24415 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
24416 * on any HTTP request
24419 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
24422 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
24426 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
24427 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
24429 remoteSort : false,
24432 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
24433 * loaded or when a record is removed. (defaults to false).
24435 pruneModifiedRecords : false,
24438 lastOptions : null,
24441 * Add Records to the Store and fires the add event.
24442 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
24444 add : function(records){
24445 records = [].concat(records);
24446 for(var i = 0, len = records.length; i < len; i++){
24447 records[i].join(this);
24449 var index = this.data.length;
24450 this.data.addAll(records);
24451 this.fireEvent("add", this, records, index);
24455 * Remove a Record from the Store and fires the remove event.
24456 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
24458 remove : function(record){
24459 var index = this.data.indexOf(record);
24460 this.data.removeAt(index);
24462 if(this.pruneModifiedRecords){
24463 this.modified.remove(record);
24465 this.fireEvent("remove", this, record, index);
24469 * Remove all Records from the Store and fires the clear event.
24471 removeAll : function(){
24473 if(this.pruneModifiedRecords){
24474 this.modified = [];
24476 this.fireEvent("clear", this);
24480 * Inserts Records to the Store at the given index and fires the add event.
24481 * @param {Number} index The start index at which to insert the passed Records.
24482 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
24484 insert : function(index, records){
24485 records = [].concat(records);
24486 for(var i = 0, len = records.length; i < len; i++){
24487 this.data.insert(index, records[i]);
24488 records[i].join(this);
24490 this.fireEvent("add", this, records, index);
24494 * Get the index within the cache of the passed Record.
24495 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
24496 * @return {Number} The index of the passed Record. Returns -1 if not found.
24498 indexOf : function(record){
24499 return this.data.indexOf(record);
24503 * Get the index within the cache of the Record with the passed id.
24504 * @param {String} id The id of the Record to find.
24505 * @return {Number} The index of the Record. Returns -1 if not found.
24507 indexOfId : function(id){
24508 return this.data.indexOfKey(id);
24512 * Get the Record with the specified id.
24513 * @param {String} id The id of the Record to find.
24514 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
24516 getById : function(id){
24517 return this.data.key(id);
24521 * Get the Record at the specified index.
24522 * @param {Number} index The index of the Record to find.
24523 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
24525 getAt : function(index){
24526 return this.data.itemAt(index);
24530 * Returns a range of Records between specified indices.
24531 * @param {Number} startIndex (optional) The starting index (defaults to 0)
24532 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
24533 * @return {Roo.data.Record[]} An array of Records
24535 getRange : function(start, end){
24536 return this.data.getRange(start, end);
24540 storeOptions : function(o){
24541 o = Roo.apply({}, o);
24544 this.lastOptions = o;
24548 * Loads the Record cache from the configured Proxy using the configured Reader.
24550 * If using remote paging, then the first load call must specify the <em>start</em>
24551 * and <em>limit</em> properties in the options.params property to establish the initial
24552 * position within the dataset, and the number of Records to cache on each read from the Proxy.
24554 * <strong>It is important to note that for remote data sources, loading is asynchronous,
24555 * and this call will return before the new data has been loaded. Perform any post-processing
24556 * in a callback function, or in a "load" event handler.</strong>
24558 * @param {Object} options An object containing properties which control loading options:<ul>
24559 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
24560 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
24561 * passed the following arguments:<ul>
24562 * <li>r : Roo.data.Record[]</li>
24563 * <li>options: Options object from the load call</li>
24564 * <li>success: Boolean success indicator</li></ul></li>
24565 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
24566 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
24569 load : function(options){
24570 options = options || {};
24571 if(this.fireEvent("beforeload", this, options) !== false){
24572 this.storeOptions(options);
24573 var p = Roo.apply(options.params || {}, this.baseParams);
24574 // if meta was not loaded from remote source.. try requesting it.
24575 if (!this.reader.metaFromRemote) {
24576 p._requestMeta = 1;
24578 if(this.sortInfo && this.remoteSort){
24579 var pn = this.paramNames;
24580 p[pn["sort"]] = this.sortInfo.field;
24581 p[pn["dir"]] = this.sortInfo.direction;
24583 if (this.multiSort) {
24584 var pn = this.paramNames;
24585 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
24588 this.proxy.load(p, this.reader, this.loadRecords, this, options);
24593 * Reloads the Record cache from the configured Proxy using the configured Reader and
24594 * the options from the last load operation performed.
24595 * @param {Object} options (optional) An object containing properties which may override the options
24596 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
24597 * the most recently used options are reused).
24599 reload : function(options){
24600 this.load(Roo.applyIf(options||{}, this.lastOptions));
24604 // Called as a callback by the Reader during a load operation.
24605 loadRecords : function(o, options, success){
24608 if(success !== false){
24609 this.fireEvent("load", this, [], options, o);
24611 if(options.callback){
24612 options.callback.call(options.scope || this, [], options, false);
24616 // if data returned failure - throw an exception.
24617 if (o.success === false) {
24618 // show a message if no listener is registered.
24619 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
24620 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
24622 // loadmask wil be hooked into this..
24623 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
24626 var r = o.records, t = o.totalRecords || r.length;
24628 this.fireEvent("beforeloadadd", this, r, options, o);
24630 if(!options || options.add !== true){
24631 if(this.pruneModifiedRecords){
24632 this.modified = [];
24634 for(var i = 0, len = r.length; i < len; i++){
24638 this.data = this.snapshot;
24639 delete this.snapshot;
24642 this.data.addAll(r);
24643 this.totalLength = t;
24645 this.fireEvent("datachanged", this);
24647 this.totalLength = Math.max(t, this.data.length+r.length);
24651 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
24653 var e = new Roo.data.Record({});
24655 e.set(this.parent.displayField, this.parent.emptyTitle);
24656 e.set(this.parent.valueField, '');
24661 this.fireEvent("load", this, r, options, o);
24662 if(options.callback){
24663 options.callback.call(options.scope || this, r, options, true);
24669 * Loads data from a passed data block. A Reader which understands the format of the data
24670 * must have been configured in the constructor.
24671 * @param {Object} data The data block from which to read the Records. The format of the data expected
24672 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
24673 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
24675 loadData : function(o, append){
24676 var r = this.reader.readRecords(o);
24677 this.loadRecords(r, {add: append}, true);
24681 * using 'cn' the nested child reader read the child array into it's child stores.
24682 * @param {Object} rec The record with a 'children array
24684 loadDataFromChildren : function(rec)
24686 this.loadData(this.reader.toLoadData(rec));
24691 * Gets the number of cached records.
24693 * <em>If using paging, this may not be the total size of the dataset. If the data object
24694 * used by the Reader contains the dataset size, then the getTotalCount() function returns
24695 * the data set size</em>
24697 getCount : function(){
24698 return this.data.length || 0;
24702 * Gets the total number of records in the dataset as returned by the server.
24704 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
24705 * the dataset size</em>
24707 getTotalCount : function(){
24708 return this.totalLength || 0;
24712 * Returns the sort state of the Store as an object with two properties:
24714 field {String} The name of the field by which the Records are sorted
24715 direction {String} The sort order, "ASC" or "DESC"
24718 getSortState : function(){
24719 return this.sortInfo;
24723 applySort : function(){
24724 if(this.sortInfo && !this.remoteSort){
24725 var s = this.sortInfo, f = s.field;
24726 var st = this.fields.get(f).sortType;
24727 var fn = function(r1, r2){
24728 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
24729 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
24731 this.data.sort(s.direction, fn);
24732 if(this.snapshot && this.snapshot != this.data){
24733 this.snapshot.sort(s.direction, fn);
24739 * Sets the default sort column and order to be used by the next load operation.
24740 * @param {String} fieldName The name of the field to sort by.
24741 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24743 setDefaultSort : function(field, dir){
24744 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
24748 * Sort the Records.
24749 * If remote sorting is used, the sort is performed on the server, and the cache is
24750 * reloaded. If local sorting is used, the cache is sorted internally.
24751 * @param {String} fieldName The name of the field to sort by.
24752 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24754 sort : function(fieldName, dir){
24755 var f = this.fields.get(fieldName);
24757 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
24759 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
24760 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
24765 this.sortToggle[f.name] = dir;
24766 this.sortInfo = {field: f.name, direction: dir};
24767 if(!this.remoteSort){
24769 this.fireEvent("datachanged", this);
24771 this.load(this.lastOptions);
24776 * Calls the specified function for each of the Records in the cache.
24777 * @param {Function} fn The function to call. The Record is passed as the first parameter.
24778 * Returning <em>false</em> aborts and exits the iteration.
24779 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
24781 each : function(fn, scope){
24782 this.data.each(fn, scope);
24786 * Gets all records modified since the last commit. Modified records are persisted across load operations
24787 * (e.g., during paging).
24788 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
24790 getModifiedRecords : function(){
24791 return this.modified;
24795 createFilterFn : function(property, value, anyMatch){
24796 if(!value.exec){ // not a regex
24797 value = String(value);
24798 if(value.length == 0){
24801 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
24803 return function(r){
24804 return value.test(r.data[property]);
24809 * Sums the value of <i>property</i> for each record between start and end and returns the result.
24810 * @param {String} property A field on your records
24811 * @param {Number} start The record index to start at (defaults to 0)
24812 * @param {Number} end The last record index to include (defaults to length - 1)
24813 * @return {Number} The sum
24815 sum : function(property, start, end){
24816 var rs = this.data.items, v = 0;
24817 start = start || 0;
24818 end = (end || end === 0) ? end : rs.length-1;
24820 for(var i = start; i <= end; i++){
24821 v += (rs[i].data[property] || 0);
24827 * Filter the records by a specified property.
24828 * @param {String} field A field on your records
24829 * @param {String/RegExp} value Either a string that the field
24830 * should start with or a RegExp to test against the field
24831 * @param {Boolean} anyMatch True to match any part not just the beginning
24833 filter : function(property, value, anyMatch){
24834 var fn = this.createFilterFn(property, value, anyMatch);
24835 return fn ? this.filterBy(fn) : this.clearFilter();
24839 * Filter by a function. The specified function will be called with each
24840 * record in this data source. If the function returns true the record is included,
24841 * otherwise it is filtered.
24842 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24843 * @param {Object} scope (optional) The scope of the function (defaults to this)
24845 filterBy : function(fn, scope){
24846 this.snapshot = this.snapshot || this.data;
24847 this.data = this.queryBy(fn, scope||this);
24848 this.fireEvent("datachanged", this);
24852 * Query the records by a specified property.
24853 * @param {String} field A field on your records
24854 * @param {String/RegExp} value Either a string that the field
24855 * should start with or a RegExp to test against the field
24856 * @param {Boolean} anyMatch True to match any part not just the beginning
24857 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24859 query : function(property, value, anyMatch){
24860 var fn = this.createFilterFn(property, value, anyMatch);
24861 return fn ? this.queryBy(fn) : this.data.clone();
24865 * Query by a function. The specified function will be called with each
24866 * record in this data source. If the function returns true the record is included
24868 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24869 * @param {Object} scope (optional) The scope of the function (defaults to this)
24870 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24872 queryBy : function(fn, scope){
24873 var data = this.snapshot || this.data;
24874 return data.filterBy(fn, scope||this);
24878 * Collects unique values for a particular dataIndex from this store.
24879 * @param {String} dataIndex The property to collect
24880 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24881 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24882 * @return {Array} An array of the unique values
24884 collect : function(dataIndex, allowNull, bypassFilter){
24885 var d = (bypassFilter === true && this.snapshot) ?
24886 this.snapshot.items : this.data.items;
24887 var v, sv, r = [], l = {};
24888 for(var i = 0, len = d.length; i < len; i++){
24889 v = d[i].data[dataIndex];
24891 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24900 * Revert to a view of the Record cache with no filtering applied.
24901 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24903 clearFilter : function(suppressEvent){
24904 if(this.snapshot && this.snapshot != this.data){
24905 this.data = this.snapshot;
24906 delete this.snapshot;
24907 if(suppressEvent !== true){
24908 this.fireEvent("datachanged", this);
24914 afterEdit : function(record){
24915 if(this.modified.indexOf(record) == -1){
24916 this.modified.push(record);
24918 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24922 afterReject : function(record){
24923 this.modified.remove(record);
24924 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24928 afterCommit : function(record){
24929 this.modified.remove(record);
24930 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24934 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24935 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24937 commitChanges : function(){
24938 var m = this.modified.slice(0);
24939 this.modified = [];
24940 for(var i = 0, len = m.length; i < len; i++){
24946 * Cancel outstanding changes on all changed records.
24948 rejectChanges : function(){
24949 var m = this.modified.slice(0);
24950 this.modified = [];
24951 for(var i = 0, len = m.length; i < len; i++){
24956 onMetaChange : function(meta, rtype, o){
24957 this.recordType = rtype;
24958 this.fields = rtype.prototype.fields;
24959 delete this.snapshot;
24960 this.sortInfo = meta.sortInfo || this.sortInfo;
24961 this.modified = [];
24962 this.fireEvent('metachange', this, this.reader.meta);
24965 moveIndex : function(data, type)
24967 var index = this.indexOf(data);
24969 var newIndex = index + type;
24973 this.insert(newIndex, data);
24978 * Ext JS Library 1.1.1
24979 * Copyright(c) 2006-2007, Ext JS, LLC.
24981 * Originally Released Under LGPL - original licence link has changed is not relivant.
24984 * <script type="text/javascript">
24988 * @class Roo.data.SimpleStore
24989 * @extends Roo.data.Store
24990 * Small helper class to make creating Stores from Array data easier.
24991 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24992 * @cfg {Array} fields An array of field definition objects, or field name strings.
24993 * @cfg {Object} an existing reader (eg. copied from another store)
24994 * @cfg {Array} data The multi-dimensional array of data
24995 * @cfg {Roo.data.DataProxy} proxy [not-required]
24996 * @cfg {Roo.data.Reader} reader [not-required]
24998 * @param {Object} config
25000 Roo.data.SimpleStore = function(config)
25002 Roo.data.SimpleStore.superclass.constructor.call(this, {
25004 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
25007 Roo.data.Record.create(config.fields)
25009 proxy : new Roo.data.MemoryProxy(config.data)
25013 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
25015 * Ext JS Library 1.1.1
25016 * Copyright(c) 2006-2007, Ext JS, LLC.
25018 * Originally Released Under LGPL - original licence link has changed is not relivant.
25021 * <script type="text/javascript">
25026 * @extends Roo.data.Store
25027 * @class Roo.data.JsonStore
25028 * Small helper class to make creating Stores for JSON data easier. <br/>
25030 var store = new Roo.data.JsonStore({
25031 url: 'get-images.php',
25033 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
25036 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
25037 * JsonReader and HttpProxy (unless inline data is provided).</b>
25038 * @cfg {Array} fields An array of field definition objects, or field name strings.
25040 * @param {Object} config
25042 Roo.data.JsonStore = function(c){
25043 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
25044 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
25045 reader: new Roo.data.JsonReader(c, c.fields)
25048 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
25050 * Ext JS Library 1.1.1
25051 * Copyright(c) 2006-2007, Ext JS, LLC.
25053 * Originally Released Under LGPL - original licence link has changed is not relivant.
25056 * <script type="text/javascript">
25060 Roo.data.Field = function(config){
25061 if(typeof config == "string"){
25062 config = {name: config};
25064 Roo.apply(this, config);
25067 this.type = "auto";
25070 var st = Roo.data.SortTypes;
25071 // named sortTypes are supported, here we look them up
25072 if(typeof this.sortType == "string"){
25073 this.sortType = st[this.sortType];
25076 // set default sortType for strings and dates
25077 if(!this.sortType){
25080 this.sortType = st.asUCString;
25083 this.sortType = st.asDate;
25086 this.sortType = st.none;
25091 var stripRe = /[\$,%]/g;
25093 // prebuilt conversion function for this field, instead of
25094 // switching every time we're reading a value
25096 var cv, dateFormat = this.dateFormat;
25101 cv = function(v){ return v; };
25104 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
25108 return v !== undefined && v !== null && v !== '' ?
25109 parseInt(String(v).replace(stripRe, ""), 10) : '';
25114 return v !== undefined && v !== null && v !== '' ?
25115 parseFloat(String(v).replace(stripRe, ""), 10) : '';
25120 cv = function(v){ return v === true || v === "true" || v == 1; };
25127 if(v instanceof Date){
25131 if(dateFormat == "timestamp"){
25132 return new Date(v*1000);
25134 return Date.parseDate(v, dateFormat);
25136 var parsed = Date.parse(v);
25137 return parsed ? new Date(parsed) : null;
25146 Roo.data.Field.prototype = {
25154 * Ext JS Library 1.1.1
25155 * Copyright(c) 2006-2007, Ext JS, LLC.
25157 * Originally Released Under LGPL - original licence link has changed is not relivant.
25160 * <script type="text/javascript">
25163 // Base class for reading structured data from a data source. This class is intended to be
25164 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
25167 * @class Roo.data.DataReader
25169 * Base class for reading structured data from a data source. This class is intended to be
25170 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
25173 Roo.data.DataReader = function(meta, recordType){
25177 this.recordType = recordType instanceof Array ?
25178 Roo.data.Record.create(recordType) : recordType;
25181 Roo.data.DataReader.prototype = {
25184 readerType : 'Data',
25186 * Create an empty record
25187 * @param {Object} data (optional) - overlay some values
25188 * @return {Roo.data.Record} record created.
25190 newRow : function(d) {
25192 this.recordType.prototype.fields.each(function(c) {
25194 case 'int' : da[c.name] = 0; break;
25195 case 'date' : da[c.name] = new Date(); break;
25196 case 'float' : da[c.name] = 0.0; break;
25197 case 'boolean' : da[c.name] = false; break;
25198 default : da[c.name] = ""; break;
25202 return new this.recordType(Roo.apply(da, d));
25208 * Ext JS Library 1.1.1
25209 * Copyright(c) 2006-2007, Ext JS, LLC.
25211 * Originally Released Under LGPL - original licence link has changed is not relivant.
25214 * <script type="text/javascript">
25218 * @class Roo.data.DataProxy
25219 * @extends Roo.util.Observable
25221 * This class is an abstract base class for implementations which provide retrieval of
25222 * unformatted data objects.<br>
25224 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
25225 * (of the appropriate type which knows how to parse the data object) to provide a block of
25226 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
25228 * Custom implementations must implement the load method as described in
25229 * {@link Roo.data.HttpProxy#load}.
25231 Roo.data.DataProxy = function(){
25234 * @event beforeload
25235 * Fires before a network request is made to retrieve a data object.
25236 * @param {Object} This DataProxy object.
25237 * @param {Object} params The params parameter to the load function.
25242 * Fires before the load method's callback is called.
25243 * @param {Object} This DataProxy object.
25244 * @param {Object} o The data object.
25245 * @param {Object} arg The callback argument object passed to the load function.
25249 * @event loadexception
25250 * Fires if an Exception occurs during data retrieval.
25251 * @param {Object} This DataProxy object.
25252 * @param {Object} o The data object.
25253 * @param {Object} arg The callback argument object passed to the load function.
25254 * @param {Object} e The Exception.
25256 loadexception : true
25258 Roo.data.DataProxy.superclass.constructor.call(this);
25261 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
25264 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
25268 * Ext JS Library 1.1.1
25269 * Copyright(c) 2006-2007, Ext JS, LLC.
25271 * Originally Released Under LGPL - original licence link has changed is not relivant.
25274 * <script type="text/javascript">
25277 * @class Roo.data.MemoryProxy
25278 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
25279 * to the Reader when its load method is called.
25281 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
25283 Roo.data.MemoryProxy = function(data){
25287 Roo.data.MemoryProxy.superclass.constructor.call(this);
25291 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
25294 * Load data from the requested source (in this case an in-memory
25295 * data object passed to the constructor), read the data object into
25296 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
25297 * process that block using the passed callback.
25298 * @param {Object} params This parameter is not used by the MemoryProxy class.
25299 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25300 * object into a block of Roo.data.Records.
25301 * @param {Function} callback The function into which to pass the block of Roo.data.records.
25302 * The function must be passed <ul>
25303 * <li>The Record block object</li>
25304 * <li>The "arg" argument from the load function</li>
25305 * <li>A boolean success indicator</li>
25307 * @param {Object} scope The scope in which to call the callback
25308 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25310 load : function(params, reader, callback, scope, arg){
25311 params = params || {};
25314 result = reader.readRecords(params.data ? params.data :this.data);
25316 this.fireEvent("loadexception", this, arg, null, e);
25317 callback.call(scope, null, arg, false);
25320 callback.call(scope, result, arg, true);
25324 update : function(params, records){
25329 * Ext JS Library 1.1.1
25330 * Copyright(c) 2006-2007, Ext JS, LLC.
25332 * Originally Released Under LGPL - original licence link has changed is not relivant.
25335 * <script type="text/javascript">
25338 * @class Roo.data.HttpProxy
25339 * @extends Roo.data.DataProxy
25340 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
25341 * configured to reference a certain URL.<br><br>
25343 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
25344 * from which the running page was served.<br><br>
25346 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
25348 * Be aware that to enable the browser to parse an XML document, the server must set
25349 * the Content-Type header in the HTTP response to "text/xml".
25351 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
25352 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
25353 * will be used to make the request.
25355 Roo.data.HttpProxy = function(conn){
25356 Roo.data.HttpProxy.superclass.constructor.call(this);
25357 // is conn a conn config or a real conn?
25359 this.useAjax = !conn || !conn.events;
25363 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
25364 // thse are take from connection...
25367 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
25370 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
25371 * extra parameters to each request made by this object. (defaults to undefined)
25374 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
25375 * to each request made by this object. (defaults to undefined)
25378 * @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)
25381 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
25384 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
25390 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
25394 * Return the {@link Roo.data.Connection} object being used by this Proxy.
25395 * @return {Connection} The Connection object. This object may be used to subscribe to events on
25396 * a finer-grained basis than the DataProxy events.
25398 getConnection : function(){
25399 return this.useAjax ? Roo.Ajax : this.conn;
25403 * Load data from the configured {@link Roo.data.Connection}, read the data object into
25404 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
25405 * process that block using the passed callback.
25406 * @param {Object} params An object containing properties which are to be used as HTTP parameters
25407 * for the request to the remote server.
25408 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25409 * object into a block of Roo.data.Records.
25410 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
25411 * The function must be passed <ul>
25412 * <li>The Record block object</li>
25413 * <li>The "arg" argument from the load function</li>
25414 * <li>A boolean success indicator</li>
25416 * @param {Object} scope The scope in which to call the callback
25417 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25419 load : function(params, reader, callback, scope, arg){
25420 if(this.fireEvent("beforeload", this, params) !== false){
25422 params : params || {},
25424 callback : callback,
25429 callback : this.loadResponse,
25433 Roo.applyIf(o, this.conn);
25434 if(this.activeRequest){
25435 Roo.Ajax.abort(this.activeRequest);
25437 this.activeRequest = Roo.Ajax.request(o);
25439 this.conn.request(o);
25442 callback.call(scope||this, null, arg, false);
25447 loadResponse : function(o, success, response){
25448 delete this.activeRequest;
25450 this.fireEvent("loadexception", this, o, response);
25451 o.request.callback.call(o.request.scope, null, o.request.arg, false);
25456 result = o.reader.read(response);
25459 o.raw = { errorMsg : response.responseText };
25460 this.fireEvent("loadexception", this, o, response, e);
25461 o.request.callback.call(o.request.scope, o, o.request.arg, false);
25465 this.fireEvent("load", this, o, o.request.arg);
25466 o.request.callback.call(o.request.scope, result, o.request.arg, true);
25470 update : function(dataSet){
25475 updateResponse : function(dataSet){
25480 * Ext JS Library 1.1.1
25481 * Copyright(c) 2006-2007, Ext JS, LLC.
25483 * Originally Released Under LGPL - original licence link has changed is not relivant.
25486 * <script type="text/javascript">
25490 * @class Roo.data.ScriptTagProxy
25491 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
25492 * other than the originating domain of the running page.<br><br>
25494 * <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
25495 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
25497 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
25498 * source code that is used as the source inside a <script> tag.<br><br>
25500 * In order for the browser to process the returned data, the server must wrap the data object
25501 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
25502 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
25503 * depending on whether the callback name was passed:
25506 boolean scriptTag = false;
25507 String cb = request.getParameter("callback");
25510 response.setContentType("text/javascript");
25512 response.setContentType("application/x-json");
25514 Writer out = response.getWriter();
25516 out.write(cb + "(");
25518 out.print(dataBlock.toJsonString());
25525 * @param {Object} config A configuration object.
25527 Roo.data.ScriptTagProxy = function(config){
25528 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
25529 Roo.apply(this, config);
25530 this.head = document.getElementsByTagName("head")[0];
25533 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
25535 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
25537 * @cfg {String} url The URL from which to request the data object.
25540 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
25544 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
25545 * the server the name of the callback function set up by the load call to process the returned data object.
25546 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
25547 * javascript output which calls this named function passing the data object as its only parameter.
25549 callbackParam : "callback",
25551 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
25552 * name to the request.
25557 * Load data from the configured URL, read the data object into
25558 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
25559 * process that block using the passed callback.
25560 * @param {Object} params An object containing properties which are to be used as HTTP parameters
25561 * for the request to the remote server.
25562 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25563 * object into a block of Roo.data.Records.
25564 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
25565 * The function must be passed <ul>
25566 * <li>The Record block object</li>
25567 * <li>The "arg" argument from the load function</li>
25568 * <li>A boolean success indicator</li>
25570 * @param {Object} scope The scope in which to call the callback
25571 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25573 load : function(params, reader, callback, scope, arg){
25574 if(this.fireEvent("beforeload", this, params) !== false){
25576 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
25578 var url = this.url;
25579 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
25581 url += "&_dc=" + (new Date().getTime());
25583 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
25586 cb : "stcCallback"+transId,
25587 scriptId : "stcScript"+transId,
25591 callback : callback,
25597 window[trans.cb] = function(o){
25598 conn.handleResponse(o, trans);
25601 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
25603 if(this.autoAbort !== false){
25607 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
25609 var script = document.createElement("script");
25610 script.setAttribute("src", url);
25611 script.setAttribute("type", "text/javascript");
25612 script.setAttribute("id", trans.scriptId);
25613 this.head.appendChild(script);
25615 this.trans = trans;
25617 callback.call(scope||this, null, arg, false);
25622 isLoading : function(){
25623 return this.trans ? true : false;
25627 * Abort the current server request.
25629 abort : function(){
25630 if(this.isLoading()){
25631 this.destroyTrans(this.trans);
25636 destroyTrans : function(trans, isLoaded){
25637 this.head.removeChild(document.getElementById(trans.scriptId));
25638 clearTimeout(trans.timeoutId);
25640 window[trans.cb] = undefined;
25642 delete window[trans.cb];
25645 // if hasn't been loaded, wait for load to remove it to prevent script error
25646 window[trans.cb] = function(){
25647 window[trans.cb] = undefined;
25649 delete window[trans.cb];
25656 handleResponse : function(o, trans){
25657 this.trans = false;
25658 this.destroyTrans(trans, true);
25661 result = trans.reader.readRecords(o);
25663 this.fireEvent("loadexception", this, o, trans.arg, e);
25664 trans.callback.call(trans.scope||window, null, trans.arg, false);
25667 this.fireEvent("load", this, o, trans.arg);
25668 trans.callback.call(trans.scope||window, result, trans.arg, true);
25672 handleFailure : function(trans){
25673 this.trans = false;
25674 this.destroyTrans(trans, false);
25675 this.fireEvent("loadexception", this, null, trans.arg);
25676 trans.callback.call(trans.scope||window, null, trans.arg, false);
25680 * Ext JS Library 1.1.1
25681 * Copyright(c) 2006-2007, Ext JS, LLC.
25683 * Originally Released Under LGPL - original licence link has changed is not relivant.
25686 * <script type="text/javascript">
25690 * @class Roo.data.JsonReader
25691 * @extends Roo.data.DataReader
25692 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
25693 * based on mappings in a provided Roo.data.Record constructor.
25695 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
25696 * in the reply previously.
25701 var RecordDef = Roo.data.Record.create([
25702 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25703 {name: 'occupation'} // This field will use "occupation" as the mapping.
25705 var myReader = new Roo.data.JsonReader({
25706 totalProperty: "results", // The property which contains the total dataset size (optional)
25707 root: "rows", // The property which contains an Array of row objects
25708 id: "id" // The property within each row object that provides an ID for the record (optional)
25712 * This would consume a JSON file like this:
25714 { 'results': 2, 'rows': [
25715 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
25716 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
25719 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
25720 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25721 * paged from the remote server.
25722 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
25723 * @cfg {String} root name of the property which contains the Array of row objects.
25724 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25725 * @cfg {Array} fields Array of field definition objects
25727 * Create a new JsonReader
25728 * @param {Object} meta Metadata configuration options
25729 * @param {Object} recordType Either an Array of field definition objects,
25730 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
25732 Roo.data.JsonReader = function(meta, recordType){
25735 // set some defaults:
25736 Roo.applyIf(meta, {
25737 totalProperty: 'total',
25738 successProperty : 'success',
25743 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25745 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
25747 readerType : 'Json',
25750 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
25751 * Used by Store query builder to append _requestMeta to params.
25754 metaFromRemote : false,
25756 * This method is only used by a DataProxy which has retrieved data from a remote server.
25757 * @param {Object} response The XHR object which contains the JSON data in its responseText.
25758 * @return {Object} data A data block which is used by an Roo.data.Store object as
25759 * a cache of Roo.data.Records.
25761 read : function(response){
25762 var json = response.responseText;
25764 var o = /* eval:var:o */ eval("("+json+")");
25766 throw {message: "JsonReader.read: Json object not found"};
25772 this.metaFromRemote = true;
25773 this.meta = o.metaData;
25774 this.recordType = Roo.data.Record.create(o.metaData.fields);
25775 this.onMetaChange(this.meta, this.recordType, o);
25777 return this.readRecords(o);
25780 // private function a store will implement
25781 onMetaChange : function(meta, recordType, o){
25788 simpleAccess: function(obj, subsc) {
25795 getJsonAccessor: function(){
25797 return function(expr) {
25799 return(re.test(expr))
25800 ? new Function("obj", "return obj." + expr)
25805 return Roo.emptyFn;
25810 * Create a data block containing Roo.data.Records from an XML document.
25811 * @param {Object} o An object which contains an Array of row objects in the property specified
25812 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
25813 * which contains the total size of the dataset.
25814 * @return {Object} data A data block which is used by an Roo.data.Store object as
25815 * a cache of Roo.data.Records.
25817 readRecords : function(o){
25819 * After any data loads, the raw JSON data is available for further custom processing.
25823 var s = this.meta, Record = this.recordType,
25824 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
25826 // Generate extraction functions for the totalProperty, the root, the id, and for each field
25828 if(s.totalProperty) {
25829 this.getTotal = this.getJsonAccessor(s.totalProperty);
25831 if(s.successProperty) {
25832 this.getSuccess = this.getJsonAccessor(s.successProperty);
25834 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
25836 var g = this.getJsonAccessor(s.id);
25837 this.getId = function(rec) {
25839 return (r === undefined || r === "") ? null : r;
25842 this.getId = function(){return null;};
25845 for(var jj = 0; jj < fl; jj++){
25847 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
25848 this.ef[jj] = this.getJsonAccessor(map);
25852 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
25853 if(s.totalProperty){
25854 var vt = parseInt(this.getTotal(o), 10);
25859 if(s.successProperty){
25860 var vs = this.getSuccess(o);
25861 if(vs === false || vs === 'false'){
25866 for(var i = 0; i < c; i++){
25869 var id = this.getId(n);
25870 for(var j = 0; j < fl; j++){
25872 var v = this.ef[j](n);
25874 Roo.log('missing convert for ' + f.name);
25878 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25882 raw : { errorMsg : "JSON Reader Error: fields or metadata not available to create Record" },
25888 var record = new Record(values, id);
25890 records[i] = record;
25896 totalRecords : totalRecords
25899 // used when loading children.. @see loadDataFromChildren
25900 toLoadData: function(rec)
25902 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25903 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25904 return { data : data, total : data.length };
25909 * Ext JS Library 1.1.1
25910 * Copyright(c) 2006-2007, Ext JS, LLC.
25912 * Originally Released Under LGPL - original licence link has changed is not relivant.
25915 * <script type="text/javascript">
25919 * @class Roo.data.XmlReader
25920 * @extends Roo.data.DataReader
25921 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25922 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25924 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25925 * header in the HTTP response must be set to "text/xml".</em>
25929 var RecordDef = Roo.data.Record.create([
25930 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25931 {name: 'occupation'} // This field will use "occupation" as the mapping.
25933 var myReader = new Roo.data.XmlReader({
25934 totalRecords: "results", // The element which contains the total dataset size (optional)
25935 record: "row", // The repeated element which contains row information
25936 id: "id" // The element within the row that provides an ID for the record (optional)
25940 * This would consume an XML file like this:
25944 <results>2</results>
25947 <name>Bill</name>
25948 <occupation>Gardener</occupation>
25952 <name>Ben</name>
25953 <occupation>Horticulturalist</occupation>
25957 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25958 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25959 * paged from the remote server.
25960 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25961 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25962 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25963 * a record identifier value.
25965 * Create a new XmlReader
25966 * @param {Object} meta Metadata configuration options
25967 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25968 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25969 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25971 Roo.data.XmlReader = function(meta, recordType){
25973 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25975 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25977 readerType : 'Xml',
25980 * This method is only used by a DataProxy which has retrieved data from a remote server.
25981 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25982 * to contain a method called 'responseXML' that returns an XML document object.
25983 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25984 * a cache of Roo.data.Records.
25986 read : function(response){
25987 var doc = response.responseXML;
25989 throw {message: "XmlReader.read: XML Document not available"};
25991 return this.readRecords(doc);
25995 * Create a data block containing Roo.data.Records from an XML document.
25996 * @param {Object} doc A parsed XML document.
25997 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25998 * a cache of Roo.data.Records.
26000 readRecords : function(doc){
26002 * After any data loads/reads, the raw XML Document is available for further custom processing.
26003 * @type XMLDocument
26005 this.xmlData = doc;
26006 var root = doc.documentElement || doc;
26007 var q = Roo.DomQuery;
26008 var recordType = this.recordType, fields = recordType.prototype.fields;
26009 var sid = this.meta.id;
26010 var totalRecords = 0, success = true;
26011 if(this.meta.totalRecords){
26012 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
26015 if(this.meta.success){
26016 var sv = q.selectValue(this.meta.success, root, true);
26017 success = sv !== false && sv !== 'false';
26020 var ns = q.select(this.meta.record, root);
26021 for(var i = 0, len = ns.length; i < len; i++) {
26024 var id = sid ? q.selectValue(sid, n) : undefined;
26025 for(var j = 0, jlen = fields.length; j < jlen; j++){
26026 var f = fields.items[j];
26027 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
26029 values[f.name] = v;
26031 var record = new recordType(values, id);
26033 records[records.length] = record;
26039 totalRecords : totalRecords || records.length
26044 * Ext JS Library 1.1.1
26045 * Copyright(c) 2006-2007, Ext JS, LLC.
26047 * Originally Released Under LGPL - original licence link has changed is not relivant.
26050 * <script type="text/javascript">
26054 * @class Roo.data.ArrayReader
26055 * @extends Roo.data.DataReader
26056 * Data reader class to create an Array of Roo.data.Record objects from an Array.
26057 * Each element of that Array represents a row of data fields. The
26058 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
26059 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
26063 var RecordDef = Roo.data.Record.create([
26064 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
26065 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
26067 var myReader = new Roo.data.ArrayReader({
26068 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
26072 * This would consume an Array like this:
26074 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
26078 * Create a new JsonReader
26079 * @param {Object} meta Metadata configuration options.
26080 * @param {Object|Array} recordType Either an Array of field definition objects
26082 * @cfg {Array} fields Array of field definition objects
26083 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
26084 * as specified to {@link Roo.data.Record#create},
26085 * or an {@link Roo.data.Record} object
26088 * created using {@link Roo.data.Record#create}.
26090 Roo.data.ArrayReader = function(meta, recordType)
26092 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
26095 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
26098 * Create a data block containing Roo.data.Records from an XML document.
26099 * @param {Object} o An Array of row objects which represents the dataset.
26100 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
26101 * a cache of Roo.data.Records.
26103 readRecords : function(o)
26105 var sid = this.meta ? this.meta.id : null;
26106 var recordType = this.recordType, fields = recordType.prototype.fields;
26109 for(var i = 0; i < root.length; i++){
26112 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
26113 for(var j = 0, jlen = fields.length; j < jlen; j++){
26114 var f = fields.items[j];
26115 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
26116 var v = n[k] !== undefined ? n[k] : f.defaultValue;
26118 values[f.name] = v;
26120 var record = new recordType(values, id);
26122 records[records.length] = record;
26126 totalRecords : records.length
26129 // used when loading children.. @see loadDataFromChildren
26130 toLoadData: function(rec)
26132 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
26133 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
26140 * Ext JS Library 1.1.1
26141 * Copyright(c) 2006-2007, Ext JS, LLC.
26143 * Originally Released Under LGPL - original licence link has changed is not relivant.
26146 * <script type="text/javascript">
26151 * @class Roo.data.Tree
26152 * @extends Roo.util.Observable
26153 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
26154 * in the tree have most standard DOM functionality.
26156 * @param {Node} root (optional) The root node
26158 Roo.data.Tree = function(root){
26159 this.nodeHash = {};
26161 * The root node for this tree
26166 this.setRootNode(root);
26171 * Fires when a new child node is appended to a node in this tree.
26172 * @param {Tree} tree The owner tree
26173 * @param {Node} parent The parent node
26174 * @param {Node} node The newly appended node
26175 * @param {Number} index The index of the newly appended node
26180 * Fires when a child node is removed from a node in this tree.
26181 * @param {Tree} tree The owner tree
26182 * @param {Node} parent The parent node
26183 * @param {Node} node The child node removed
26188 * Fires when a node is moved to a new location in the tree
26189 * @param {Tree} tree The owner tree
26190 * @param {Node} node The node moved
26191 * @param {Node} oldParent The old parent of this node
26192 * @param {Node} newParent The new parent of this node
26193 * @param {Number} index The index it was moved to
26198 * Fires when a new child node is inserted in a node in this tree.
26199 * @param {Tree} tree The owner tree
26200 * @param {Node} parent The parent node
26201 * @param {Node} node The child node inserted
26202 * @param {Node} refNode The child node the node was inserted before
26206 * @event beforeappend
26207 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
26208 * @param {Tree} tree The owner tree
26209 * @param {Node} parent The parent node
26210 * @param {Node} node The child node to be appended
26212 "beforeappend" : true,
26214 * @event beforeremove
26215 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
26216 * @param {Tree} tree The owner tree
26217 * @param {Node} parent The parent node
26218 * @param {Node} node The child node to be removed
26220 "beforeremove" : true,
26222 * @event beforemove
26223 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
26224 * @param {Tree} tree The owner tree
26225 * @param {Node} node The node being moved
26226 * @param {Node} oldParent The parent of the node
26227 * @param {Node} newParent The new parent the node is moving to
26228 * @param {Number} index The index it is being moved to
26230 "beforemove" : true,
26232 * @event beforeinsert
26233 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
26234 * @param {Tree} tree The owner tree
26235 * @param {Node} parent The parent node
26236 * @param {Node} node The child node to be inserted
26237 * @param {Node} refNode The child node the node is being inserted before
26239 "beforeinsert" : true
26242 Roo.data.Tree.superclass.constructor.call(this);
26245 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
26246 pathSeparator: "/",
26248 proxyNodeEvent : function(){
26249 return this.fireEvent.apply(this, arguments);
26253 * Returns the root node for this tree.
26256 getRootNode : function(){
26261 * Sets the root node for this tree.
26262 * @param {Node} node
26265 setRootNode : function(node){
26267 node.ownerTree = this;
26268 node.isRoot = true;
26269 this.registerNode(node);
26274 * Gets a node in this tree by its id.
26275 * @param {String} id
26278 getNodeById : function(id){
26279 return this.nodeHash[id];
26282 registerNode : function(node){
26283 this.nodeHash[node.id] = node;
26286 unregisterNode : function(node){
26287 delete this.nodeHash[node.id];
26290 toString : function(){
26291 return "[Tree"+(this.id?" "+this.id:"")+"]";
26296 * @class Roo.data.Node
26297 * @extends Roo.util.Observable
26298 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
26299 * @cfg {String} id The id for this node. If one is not specified, one is generated.
26301 * @param {Object} attributes The attributes/config for the node
26303 Roo.data.Node = function(attributes){
26305 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
26308 this.attributes = attributes || {};
26309 this.leaf = this.attributes.leaf;
26311 * The node id. @type String
26313 this.id = this.attributes.id;
26315 this.id = Roo.id(null, "ynode-");
26316 this.attributes.id = this.id;
26321 * All child nodes of this node. @type Array
26323 this.childNodes = [];
26324 if(!this.childNodes.indexOf){ // indexOf is a must
26325 this.childNodes.indexOf = function(o){
26326 for(var i = 0, len = this.length; i < len; i++){
26335 * The parent node for this node. @type Node
26337 this.parentNode = null;
26339 * The first direct child node of this node, or null if this node has no child nodes. @type Node
26341 this.firstChild = null;
26343 * The last direct child node of this node, or null if this node has no child nodes. @type Node
26345 this.lastChild = null;
26347 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
26349 this.previousSibling = null;
26351 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
26353 this.nextSibling = null;
26358 * Fires when a new child node is appended
26359 * @param {Tree} tree The owner tree
26360 * @param {Node} this This node
26361 * @param {Node} node The newly appended node
26362 * @param {Number} index The index of the newly appended node
26367 * Fires when a child node is removed
26368 * @param {Tree} tree The owner tree
26369 * @param {Node} this This node
26370 * @param {Node} node The removed node
26375 * Fires when this node is moved to a new location in the tree
26376 * @param {Tree} tree The owner tree
26377 * @param {Node} this This node
26378 * @param {Node} oldParent The old parent of this node
26379 * @param {Node} newParent The new parent of this node
26380 * @param {Number} index The index it was moved to
26385 * Fires when a new child node is inserted.
26386 * @param {Tree} tree The owner tree
26387 * @param {Node} this This node
26388 * @param {Node} node The child node inserted
26389 * @param {Node} refNode The child node the node was inserted before
26393 * @event beforeappend
26394 * Fires before a new child is appended, return false to cancel the append.
26395 * @param {Tree} tree The owner tree
26396 * @param {Node} this This node
26397 * @param {Node} node The child node to be appended
26399 "beforeappend" : true,
26401 * @event beforeremove
26402 * Fires before a child is removed, return false to cancel the remove.
26403 * @param {Tree} tree The owner tree
26404 * @param {Node} this This node
26405 * @param {Node} node The child node to be removed
26407 "beforeremove" : true,
26409 * @event beforemove
26410 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
26411 * @param {Tree} tree The owner tree
26412 * @param {Node} this This node
26413 * @param {Node} oldParent The parent of this node
26414 * @param {Node} newParent The new parent this node is moving to
26415 * @param {Number} index The index it is being moved to
26417 "beforemove" : true,
26419 * @event beforeinsert
26420 * Fires before a new child is inserted, return false to cancel the insert.
26421 * @param {Tree} tree The owner tree
26422 * @param {Node} this This node
26423 * @param {Node} node The child node to be inserted
26424 * @param {Node} refNode The child node the node is being inserted before
26426 "beforeinsert" : true
26428 this.listeners = this.attributes.listeners;
26429 Roo.data.Node.superclass.constructor.call(this);
26432 Roo.extend(Roo.data.Node, Roo.util.Observable, {
26433 fireEvent : function(evtName){
26434 // first do standard event for this node
26435 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
26438 // then bubble it up to the tree if the event wasn't cancelled
26439 var ot = this.getOwnerTree();
26441 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
26449 * Returns true if this node is a leaf
26450 * @return {Boolean}
26452 isLeaf : function(){
26453 return this.leaf === true;
26457 setFirstChild : function(node){
26458 this.firstChild = node;
26462 setLastChild : function(node){
26463 this.lastChild = node;
26468 * Returns true if this node is the last child of its parent
26469 * @return {Boolean}
26471 isLast : function(){
26472 return (!this.parentNode ? true : this.parentNode.lastChild == this);
26476 * Returns true if this node is the first child of its parent
26477 * @return {Boolean}
26479 isFirst : function(){
26480 return (!this.parentNode ? true : this.parentNode.firstChild == this);
26483 hasChildNodes : function(){
26484 return !this.isLeaf() && this.childNodes.length > 0;
26488 * Insert node(s) as the last child node of this node.
26489 * @param {Node/Array} node The node or Array of nodes to append
26490 * @return {Node} The appended node if single append, or null if an array was passed
26492 appendChild : function(node){
26494 if(node instanceof Array){
26496 }else if(arguments.length > 1){
26500 // if passed an array or multiple args do them one by one
26502 for(var i = 0, len = multi.length; i < len; i++) {
26503 this.appendChild(multi[i]);
26506 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
26509 var index = this.childNodes.length;
26510 var oldParent = node.parentNode;
26511 // it's a move, make sure we move it cleanly
26513 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
26516 oldParent.removeChild(node);
26519 index = this.childNodes.length;
26521 this.setFirstChild(node);
26523 this.childNodes.push(node);
26524 node.parentNode = this;
26525 var ps = this.childNodes[index-1];
26527 node.previousSibling = ps;
26528 ps.nextSibling = node;
26530 node.previousSibling = null;
26532 node.nextSibling = null;
26533 this.setLastChild(node);
26534 node.setOwnerTree(this.getOwnerTree());
26535 this.fireEvent("append", this.ownerTree, this, node, index);
26536 if(this.ownerTree) {
26537 this.ownerTree.fireEvent("appendnode", this, node, index);
26540 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
26547 * Removes a child node from this node.
26548 * @param {Node} node The node to remove
26549 * @return {Node} The removed node
26551 removeChild : function(node){
26552 var index = this.childNodes.indexOf(node);
26556 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
26560 // remove it from childNodes collection
26561 this.childNodes.splice(index, 1);
26564 if(node.previousSibling){
26565 node.previousSibling.nextSibling = node.nextSibling;
26567 if(node.nextSibling){
26568 node.nextSibling.previousSibling = node.previousSibling;
26571 // update child refs
26572 if(this.firstChild == node){
26573 this.setFirstChild(node.nextSibling);
26575 if(this.lastChild == node){
26576 this.setLastChild(node.previousSibling);
26579 node.setOwnerTree(null);
26580 // clear any references from the node
26581 node.parentNode = null;
26582 node.previousSibling = null;
26583 node.nextSibling = null;
26584 this.fireEvent("remove", this.ownerTree, this, node);
26589 * Inserts the first node before the second node in this nodes childNodes collection.
26590 * @param {Node} node The node to insert
26591 * @param {Node} refNode The node to insert before (if null the node is appended)
26592 * @return {Node} The inserted node
26594 insertBefore : function(node, refNode){
26595 if(!refNode){ // like standard Dom, refNode can be null for append
26596 return this.appendChild(node);
26599 if(node == refNode){
26603 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
26606 var index = this.childNodes.indexOf(refNode);
26607 var oldParent = node.parentNode;
26608 var refIndex = index;
26610 // when moving internally, indexes will change after remove
26611 if(oldParent == this && this.childNodes.indexOf(node) < index){
26615 // it's a move, make sure we move it cleanly
26617 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
26620 oldParent.removeChild(node);
26623 this.setFirstChild(node);
26625 this.childNodes.splice(refIndex, 0, node);
26626 node.parentNode = this;
26627 var ps = this.childNodes[refIndex-1];
26629 node.previousSibling = ps;
26630 ps.nextSibling = node;
26632 node.previousSibling = null;
26634 node.nextSibling = refNode;
26635 refNode.previousSibling = node;
26636 node.setOwnerTree(this.getOwnerTree());
26637 this.fireEvent("insert", this.ownerTree, this, node, refNode);
26639 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
26645 * Returns the child node at the specified index.
26646 * @param {Number} index
26649 item : function(index){
26650 return this.childNodes[index];
26654 * Replaces one child node in this node with another.
26655 * @param {Node} newChild The replacement node
26656 * @param {Node} oldChild The node to replace
26657 * @return {Node} The replaced node
26659 replaceChild : function(newChild, oldChild){
26660 this.insertBefore(newChild, oldChild);
26661 this.removeChild(oldChild);
26666 * Returns the index of a child node
26667 * @param {Node} node
26668 * @return {Number} The index of the node or -1 if it was not found
26670 indexOf : function(child){
26671 return this.childNodes.indexOf(child);
26675 * Returns the tree this node is in.
26678 getOwnerTree : function(){
26679 // if it doesn't have one, look for one
26680 if(!this.ownerTree){
26684 this.ownerTree = p.ownerTree;
26690 return this.ownerTree;
26694 * Returns depth of this node (the root node has a depth of 0)
26697 getDepth : function(){
26700 while(p.parentNode){
26708 setOwnerTree : function(tree){
26709 // if it's move, we need to update everyone
26710 if(tree != this.ownerTree){
26711 if(this.ownerTree){
26712 this.ownerTree.unregisterNode(this);
26714 this.ownerTree = tree;
26715 var cs = this.childNodes;
26716 for(var i = 0, len = cs.length; i < len; i++) {
26717 cs[i].setOwnerTree(tree);
26720 tree.registerNode(this);
26726 * Returns the path for this node. The path can be used to expand or select this node programmatically.
26727 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
26728 * @return {String} The path
26730 getPath : function(attr){
26731 attr = attr || "id";
26732 var p = this.parentNode;
26733 var b = [this.attributes[attr]];
26735 b.unshift(p.attributes[attr]);
26738 var sep = this.getOwnerTree().pathSeparator;
26739 return sep + b.join(sep);
26743 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26744 * function call will be the scope provided or the current node. The arguments to the function
26745 * will be the args provided or the current node. If the function returns false at any point,
26746 * the bubble is stopped.
26747 * @param {Function} fn The function to call
26748 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26749 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26751 bubble : function(fn, scope, args){
26754 if(fn.call(scope || p, args || p) === false){
26762 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26763 * function call will be the scope provided or the current node. The arguments to the function
26764 * will be the args provided or the current node. If the function returns false at any point,
26765 * the cascade is stopped on that branch.
26766 * @param {Function} fn The function to call
26767 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26768 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26770 cascade : function(fn, scope, args){
26771 if(fn.call(scope || this, args || this) !== false){
26772 var cs = this.childNodes;
26773 for(var i = 0, len = cs.length; i < len; i++) {
26774 cs[i].cascade(fn, scope, args);
26780 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
26781 * function call will be the scope provided or the current node. The arguments to the function
26782 * will be the args provided or the current node. If the function returns false at any point,
26783 * the iteration stops.
26784 * @param {Function} fn The function to call
26785 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26786 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26788 eachChild : function(fn, scope, args){
26789 var cs = this.childNodes;
26790 for(var i = 0, len = cs.length; i < len; i++) {
26791 if(fn.call(scope || this, args || cs[i]) === false){
26798 * Finds the first child that has the attribute with the specified value.
26799 * @param {String} attribute The attribute name
26800 * @param {Mixed} value The value to search for
26801 * @return {Node} The found child or null if none was found
26803 findChild : function(attribute, value){
26804 var cs = this.childNodes;
26805 for(var i = 0, len = cs.length; i < len; i++) {
26806 if(cs[i].attributes[attribute] == value){
26814 * Finds the first child by a custom function. The child matches if the function passed
26816 * @param {Function} fn
26817 * @param {Object} scope (optional)
26818 * @return {Node} The found child or null if none was found
26820 findChildBy : function(fn, scope){
26821 var cs = this.childNodes;
26822 for(var i = 0, len = cs.length; i < len; i++) {
26823 if(fn.call(scope||cs[i], cs[i]) === true){
26831 * Sorts this nodes children using the supplied sort function
26832 * @param {Function} fn
26833 * @param {Object} scope (optional)
26835 sort : function(fn, scope){
26836 var cs = this.childNodes;
26837 var len = cs.length;
26839 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
26841 for(var i = 0; i < len; i++){
26843 n.previousSibling = cs[i-1];
26844 n.nextSibling = cs[i+1];
26846 this.setFirstChild(n);
26849 this.setLastChild(n);
26856 * Returns true if this node is an ancestor (at any point) of the passed node.
26857 * @param {Node} node
26858 * @return {Boolean}
26860 contains : function(node){
26861 return node.isAncestor(this);
26865 * Returns true if the passed node is an ancestor (at any point) of this node.
26866 * @param {Node} node
26867 * @return {Boolean}
26869 isAncestor : function(node){
26870 var p = this.parentNode;
26880 toString : function(){
26881 return "[Node"+(this.id?" "+this.id:"")+"]";
26885 * Ext JS Library 1.1.1
26886 * Copyright(c) 2006-2007, Ext JS, LLC.
26888 * Originally Released Under LGPL - original licence link has changed is not relivant.
26891 * <script type="text/javascript">
26896 * @class Roo.Shadow
26897 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26898 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26899 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26901 * Create a new Shadow
26902 * @param {Object} config The config object
26904 Roo.Shadow = function(config){
26905 Roo.apply(this, config);
26906 if(typeof this.mode != "string"){
26907 this.mode = this.defaultMode;
26909 var o = this.offset, a = {h: 0};
26910 var rad = Math.floor(this.offset/2);
26911 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26917 a.l -= this.offset + rad;
26918 a.t -= this.offset + rad;
26929 a.l -= (this.offset - rad);
26930 a.t -= this.offset + rad;
26932 a.w -= (this.offset - rad)*2;
26943 a.l -= (this.offset - rad);
26944 a.t -= (this.offset - rad);
26946 a.w -= (this.offset + rad + 1);
26947 a.h -= (this.offset + rad);
26956 Roo.Shadow.prototype = {
26958 * @cfg {String} mode
26959 * The shadow display mode. Supports the following options:<br />
26960 * sides: Shadow displays on both sides and bottom only<br />
26961 * frame: Shadow displays equally on all four sides<br />
26962 * drop: Traditional bottom-right drop shadow (default)
26966 * @cfg {String} offset
26967 * The number of pixels to offset the shadow from the element (defaults to 4)
26972 defaultMode: "drop",
26975 * Displays the shadow under the target element
26976 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26978 show : function(target){
26979 target = Roo.get(target);
26981 this.el = Roo.Shadow.Pool.pull();
26982 if(this.el.dom.nextSibling != target.dom){
26983 this.el.insertBefore(target);
26986 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26988 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26991 target.getLeft(true),
26992 target.getTop(true),
26996 this.el.dom.style.display = "block";
27000 * Returns true if the shadow is visible, else false
27002 isVisible : function(){
27003 return this.el ? true : false;
27007 * Direct alignment when values are already available. Show must be called at least once before
27008 * calling this method to ensure it is initialized.
27009 * @param {Number} left The target element left position
27010 * @param {Number} top The target element top position
27011 * @param {Number} width The target element width
27012 * @param {Number} height The target element height
27014 realign : function(l, t, w, h){
27018 var a = this.adjusts, d = this.el.dom, s = d.style;
27020 s.left = (l+a.l)+"px";
27021 s.top = (t+a.t)+"px";
27022 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
27024 if(s.width != sws || s.height != shs){
27028 var cn = d.childNodes;
27029 var sww = Math.max(0, (sw-12))+"px";
27030 cn[0].childNodes[1].style.width = sww;
27031 cn[1].childNodes[1].style.width = sww;
27032 cn[2].childNodes[1].style.width = sww;
27033 cn[1].style.height = Math.max(0, (sh-12))+"px";
27039 * Hides this shadow
27043 this.el.dom.style.display = "none";
27044 Roo.Shadow.Pool.push(this.el);
27050 * Adjust the z-index of this shadow
27051 * @param {Number} zindex The new z-index
27053 setZIndex : function(z){
27056 this.el.setStyle("z-index", z);
27061 // Private utility class that manages the internal Shadow cache
27062 Roo.Shadow.Pool = function(){
27064 var markup = Roo.isIE ?
27065 '<div class="x-ie-shadow"></div>' :
27066 '<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>';
27069 var sh = p.shift();
27071 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
27072 sh.autoBoxAdjust = false;
27077 push : function(sh){
27083 * Ext JS Library 1.1.1
27084 * Copyright(c) 2006-2007, Ext JS, LLC.
27086 * Originally Released Under LGPL - original licence link has changed is not relivant.
27089 * <script type="text/javascript">
27094 * @class Roo.SplitBar
27095 * @extends Roo.util.Observable
27096 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
27100 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
27101 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
27102 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
27103 split.minSize = 100;
27104 split.maxSize = 600;
27105 split.animate = true;
27106 split.on('moved', splitterMoved);
27109 * Create a new SplitBar
27110 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
27111 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
27112 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
27113 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
27114 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
27115 position of the SplitBar).
27117 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
27120 this.el = Roo.get(dragElement, true);
27121 this.el.dom.unselectable = "on";
27123 this.resizingEl = Roo.get(resizingElement, true);
27127 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
27128 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
27131 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
27134 * The minimum size of the resizing element. (Defaults to 0)
27140 * The maximum size of the resizing element. (Defaults to 2000)
27143 this.maxSize = 2000;
27146 * Whether to animate the transition to the new size
27149 this.animate = false;
27152 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
27155 this.useShim = false;
27160 if(!existingProxy){
27162 this.proxy = Roo.SplitBar.createProxy(this.orientation);
27164 this.proxy = Roo.get(existingProxy).dom;
27167 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
27170 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
27173 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
27176 this.dragSpecs = {};
27179 * @private The adapter to use to positon and resize elements
27181 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
27182 this.adapter.init(this);
27184 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27186 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
27187 this.el.addClass("x-splitbar-h");
27190 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
27191 this.el.addClass("x-splitbar-v");
27197 * Fires when the splitter is moved (alias for {@link #event-moved})
27198 * @param {Roo.SplitBar} this
27199 * @param {Number} newSize the new width or height
27204 * Fires when the splitter is moved
27205 * @param {Roo.SplitBar} this
27206 * @param {Number} newSize the new width or height
27210 * @event beforeresize
27211 * Fires before the splitter is dragged
27212 * @param {Roo.SplitBar} this
27214 "beforeresize" : true,
27216 "beforeapply" : true
27219 Roo.util.Observable.call(this);
27222 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
27223 onStartProxyDrag : function(x, y){
27224 this.fireEvent("beforeresize", this);
27226 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
27228 o.enableDisplayMode("block");
27229 // all splitbars share the same overlay
27230 Roo.SplitBar.prototype.overlay = o;
27232 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27233 this.overlay.show();
27234 Roo.get(this.proxy).setDisplayed("block");
27235 var size = this.adapter.getElementSize(this);
27236 this.activeMinSize = this.getMinimumSize();;
27237 this.activeMaxSize = this.getMaximumSize();;
27238 var c1 = size - this.activeMinSize;
27239 var c2 = Math.max(this.activeMaxSize - size, 0);
27240 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27241 this.dd.resetConstraints();
27242 this.dd.setXConstraint(
27243 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
27244 this.placement == Roo.SplitBar.LEFT ? c2 : c1
27246 this.dd.setYConstraint(0, 0);
27248 this.dd.resetConstraints();
27249 this.dd.setXConstraint(0, 0);
27250 this.dd.setYConstraint(
27251 this.placement == Roo.SplitBar.TOP ? c1 : c2,
27252 this.placement == Roo.SplitBar.TOP ? c2 : c1
27255 this.dragSpecs.startSize = size;
27256 this.dragSpecs.startPoint = [x, y];
27257 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
27261 * @private Called after the drag operation by the DDProxy
27263 onEndProxyDrag : function(e){
27264 Roo.get(this.proxy).setDisplayed(false);
27265 var endPoint = Roo.lib.Event.getXY(e);
27267 this.overlay.hide();
27270 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27271 newSize = this.dragSpecs.startSize +
27272 (this.placement == Roo.SplitBar.LEFT ?
27273 endPoint[0] - this.dragSpecs.startPoint[0] :
27274 this.dragSpecs.startPoint[0] - endPoint[0]
27277 newSize = this.dragSpecs.startSize +
27278 (this.placement == Roo.SplitBar.TOP ?
27279 endPoint[1] - this.dragSpecs.startPoint[1] :
27280 this.dragSpecs.startPoint[1] - endPoint[1]
27283 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
27284 if(newSize != this.dragSpecs.startSize){
27285 if(this.fireEvent('beforeapply', this, newSize) !== false){
27286 this.adapter.setElementSize(this, newSize);
27287 this.fireEvent("moved", this, newSize);
27288 this.fireEvent("resize", this, newSize);
27294 * Get the adapter this SplitBar uses
27295 * @return The adapter object
27297 getAdapter : function(){
27298 return this.adapter;
27302 * Set the adapter this SplitBar uses
27303 * @param {Object} adapter A SplitBar adapter object
27305 setAdapter : function(adapter){
27306 this.adapter = adapter;
27307 this.adapter.init(this);
27311 * Gets the minimum size for the resizing element
27312 * @return {Number} The minimum size
27314 getMinimumSize : function(){
27315 return this.minSize;
27319 * Sets the minimum size for the resizing element
27320 * @param {Number} minSize The minimum size
27322 setMinimumSize : function(minSize){
27323 this.minSize = minSize;
27327 * Gets the maximum size for the resizing element
27328 * @return {Number} The maximum size
27330 getMaximumSize : function(){
27331 return this.maxSize;
27335 * Sets the maximum size for the resizing element
27336 * @param {Number} maxSize The maximum size
27338 setMaximumSize : function(maxSize){
27339 this.maxSize = maxSize;
27343 * Sets the initialize size for the resizing element
27344 * @param {Number} size The initial size
27346 setCurrentSize : function(size){
27347 var oldAnimate = this.animate;
27348 this.animate = false;
27349 this.adapter.setElementSize(this, size);
27350 this.animate = oldAnimate;
27354 * Destroy this splitbar.
27355 * @param {Boolean} removeEl True to remove the element
27357 destroy : function(removeEl){
27359 this.shim.remove();
27362 this.proxy.parentNode.removeChild(this.proxy);
27370 * @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.
27372 Roo.SplitBar.createProxy = function(dir){
27373 var proxy = new Roo.Element(document.createElement("div"));
27374 proxy.unselectable();
27375 var cls = 'x-splitbar-proxy';
27376 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
27377 document.body.appendChild(proxy.dom);
27382 * @class Roo.SplitBar.BasicLayoutAdapter
27383 * Default Adapter. It assumes the splitter and resizing element are not positioned
27384 * elements and only gets/sets the width of the element. Generally used for table based layouts.
27386 Roo.SplitBar.BasicLayoutAdapter = function(){
27389 Roo.SplitBar.BasicLayoutAdapter.prototype = {
27390 // do nothing for now
27391 init : function(s){
27395 * Called before drag operations to get the current size of the resizing element.
27396 * @param {Roo.SplitBar} s The SplitBar using this adapter
27398 getElementSize : function(s){
27399 if(s.orientation == Roo.SplitBar.HORIZONTAL){
27400 return s.resizingEl.getWidth();
27402 return s.resizingEl.getHeight();
27407 * Called after drag operations to set the size of the resizing element.
27408 * @param {Roo.SplitBar} s The SplitBar using this adapter
27409 * @param {Number} newSize The new size to set
27410 * @param {Function} onComplete A function to be invoked when resizing is complete
27412 setElementSize : function(s, newSize, onComplete){
27413 if(s.orientation == Roo.SplitBar.HORIZONTAL){
27415 s.resizingEl.setWidth(newSize);
27417 onComplete(s, newSize);
27420 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
27425 s.resizingEl.setHeight(newSize);
27427 onComplete(s, newSize);
27430 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
27437 *@class Roo.SplitBar.AbsoluteLayoutAdapter
27438 * @extends Roo.SplitBar.BasicLayoutAdapter
27439 * Adapter that moves the splitter element to align with the resized sizing element.
27440 * Used with an absolute positioned SplitBar.
27441 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
27442 * document.body, make sure you assign an id to the body element.
27444 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
27445 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
27446 this.container = Roo.get(container);
27449 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
27450 init : function(s){
27451 this.basic.init(s);
27454 getElementSize : function(s){
27455 return this.basic.getElementSize(s);
27458 setElementSize : function(s, newSize, onComplete){
27459 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
27462 moveSplitter : function(s){
27463 var yes = Roo.SplitBar;
27464 switch(s.placement){
27466 s.el.setX(s.resizingEl.getRight());
27469 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
27472 s.el.setY(s.resizingEl.getBottom());
27475 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
27482 * Orientation constant - Create a vertical SplitBar
27486 Roo.SplitBar.VERTICAL = 1;
27489 * Orientation constant - Create a horizontal SplitBar
27493 Roo.SplitBar.HORIZONTAL = 2;
27496 * Placement constant - The resizing element is to the left of the splitter element
27500 Roo.SplitBar.LEFT = 1;
27503 * Placement constant - The resizing element is to the right of the splitter element
27507 Roo.SplitBar.RIGHT = 2;
27510 * Placement constant - The resizing element is positioned above the splitter element
27514 Roo.SplitBar.TOP = 3;
27517 * Placement constant - The resizing element is positioned under splitter element
27521 Roo.SplitBar.BOTTOM = 4;
27524 * Ext JS Library 1.1.1
27525 * Copyright(c) 2006-2007, Ext JS, LLC.
27527 * Originally Released Under LGPL - original licence link has changed is not relivant.
27530 * <script type="text/javascript">
27535 * @extends Roo.util.Observable
27536 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
27537 * This class also supports single and multi selection modes. <br>
27538 * Create a data model bound view:
27540 var store = new Roo.data.Store(...);
27542 var view = new Roo.View({
27544 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
27546 singleSelect: true,
27547 selectedClass: "ydataview-selected",
27551 // listen for node click?
27552 view.on("click", function(vw, index, node, e){
27553 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27557 dataModel.load("foobar.xml");
27559 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
27561 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
27562 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
27564 * Note: old style constructor is still suported (container, template, config)
27567 * Create a new View
27568 * @param {Object} config The config object
27571 Roo.View = function(config, depreciated_tpl, depreciated_config){
27573 this.parent = false;
27575 if (typeof(depreciated_tpl) == 'undefined') {
27576 // new way.. - universal constructor.
27577 Roo.apply(this, config);
27578 this.el = Roo.get(this.el);
27581 this.el = Roo.get(config);
27582 this.tpl = depreciated_tpl;
27583 Roo.apply(this, depreciated_config);
27585 this.wrapEl = this.el.wrap().wrap();
27586 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
27589 if(typeof(this.tpl) == "string"){
27590 this.tpl = new Roo.Template(this.tpl);
27592 // support xtype ctors..
27593 this.tpl = new Roo.factory(this.tpl, Roo);
27597 this.tpl.compile();
27602 * @event beforeclick
27603 * Fires before a click is processed. Returns false to cancel the default action.
27604 * @param {Roo.View} this
27605 * @param {Number} index The index of the target node
27606 * @param {HTMLElement} node The target node
27607 * @param {Roo.EventObject} e The raw event object
27609 "beforeclick" : true,
27612 * Fires when a template node is clicked.
27613 * @param {Roo.View} this
27614 * @param {Number} index The index of the target node
27615 * @param {HTMLElement} node The target node
27616 * @param {Roo.EventObject} e The raw event object
27621 * Fires when a template node is double clicked.
27622 * @param {Roo.View} this
27623 * @param {Number} index The index of the target node
27624 * @param {HTMLElement} node The target node
27625 * @param {Roo.EventObject} e The raw event object
27629 * @event contextmenu
27630 * Fires when a template node is right clicked.
27631 * @param {Roo.View} this
27632 * @param {Number} index The index of the target node
27633 * @param {HTMLElement} node The target node
27634 * @param {Roo.EventObject} e The raw event object
27636 "contextmenu" : true,
27638 * @event selectionchange
27639 * Fires when the selected nodes change.
27640 * @param {Roo.View} this
27641 * @param {Array} selections Array of the selected nodes
27643 "selectionchange" : true,
27646 * @event beforeselect
27647 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
27648 * @param {Roo.View} this
27649 * @param {HTMLElement} node The node to be selected
27650 * @param {Array} selections Array of currently selected nodes
27652 "beforeselect" : true,
27654 * @event preparedata
27655 * Fires on every row to render, to allow you to change the data.
27656 * @param {Roo.View} this
27657 * @param {Object} data to be rendered (change this)
27659 "preparedata" : true
27667 "click": this.onClick,
27668 "dblclick": this.onDblClick,
27669 "contextmenu": this.onContextMenu,
27673 this.selections = [];
27675 this.cmp = new Roo.CompositeElementLite([]);
27677 this.store = Roo.factory(this.store, Roo.data);
27678 this.setStore(this.store, true);
27681 if ( this.footer && this.footer.xtype) {
27683 var fctr = this.wrapEl.appendChild(document.createElement("div"));
27685 this.footer.dataSource = this.store;
27686 this.footer.container = fctr;
27687 this.footer = Roo.factory(this.footer, Roo);
27688 fctr.insertFirst(this.el);
27690 // this is a bit insane - as the paging toolbar seems to detach the el..
27691 // dom.parentNode.parentNode.parentNode
27692 // they get detached?
27696 Roo.View.superclass.constructor.call(this);
27701 Roo.extend(Roo.View, Roo.util.Observable, {
27704 * @cfg {Roo.data.Store} store Data store to load data from.
27709 * @cfg {String|Roo.Element} el The container element.
27714 * @cfg {String|Roo.Template} tpl The template used by this View
27718 * @cfg {String} dataName the named area of the template to use as the data area
27719 * Works with domtemplates roo-name="name"
27723 * @cfg {String} selectedClass The css class to add to selected nodes
27725 selectedClass : "x-view-selected",
27727 * @cfg {String} emptyText The empty text to show when nothing is loaded.
27732 * @cfg {String} text to display on mask (default Loading)
27736 * @cfg {Boolean} multiSelect Allow multiple selection
27738 multiSelect : false,
27740 * @cfg {Boolean} singleSelect Allow single selection
27742 singleSelect: false,
27745 * @cfg {Boolean} toggleSelect - selecting
27747 toggleSelect : false,
27750 * @cfg {Boolean} tickable - selecting
27755 * Returns the element this view is bound to.
27756 * @return {Roo.Element}
27758 getEl : function(){
27759 return this.wrapEl;
27765 * Refreshes the view. - called by datachanged on the store. - do not call directly.
27767 refresh : function(){
27768 //Roo.log('refresh');
27771 // if we are using something like 'domtemplate', then
27772 // the what gets used is:
27773 // t.applySubtemplate(NAME, data, wrapping data..)
27774 // the outer template then get' applied with
27775 // the store 'extra data'
27776 // and the body get's added to the
27777 // roo-name="data" node?
27778 // <span class='roo-tpl-{name}'></span> ?????
27782 this.clearSelections();
27783 this.el.update("");
27785 var records = this.store.getRange();
27786 if(records.length < 1) {
27788 // is this valid?? = should it render a template??
27790 this.el.update(this.emptyText);
27794 if (this.dataName) {
27795 this.el.update(t.apply(this.store.meta)); //????
27796 el = this.el.child('.roo-tpl-' + this.dataName);
27799 for(var i = 0, len = records.length; i < len; i++){
27800 var data = this.prepareData(records[i].data, i, records[i]);
27801 this.fireEvent("preparedata", this, data, i, records[i]);
27803 var d = Roo.apply({}, data);
27806 Roo.apply(d, {'roo-id' : Roo.id()});
27810 Roo.each(this.parent.item, function(item){
27811 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
27814 Roo.apply(d, {'roo-data-checked' : 'checked'});
27818 html[html.length] = Roo.util.Format.trim(
27820 t.applySubtemplate(this.dataName, d, this.store.meta) :
27827 el.update(html.join(""));
27828 this.nodes = el.dom.childNodes;
27829 this.updateIndexes(0);
27834 * Function to override to reformat the data that is sent to
27835 * the template for each node.
27836 * DEPRICATED - use the preparedata event handler.
27837 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
27838 * a JSON object for an UpdateManager bound view).
27840 prepareData : function(data, index, record)
27842 this.fireEvent("preparedata", this, data, index, record);
27846 onUpdate : function(ds, record){
27847 // Roo.log('on update');
27848 this.clearSelections();
27849 var index = this.store.indexOf(record);
27850 var n = this.nodes[index];
27851 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
27852 n.parentNode.removeChild(n);
27853 this.updateIndexes(index, index);
27859 onAdd : function(ds, records, index)
27861 //Roo.log(['on Add', ds, records, index] );
27862 this.clearSelections();
27863 if(this.nodes.length == 0){
27867 var n = this.nodes[index];
27868 for(var i = 0, len = records.length; i < len; i++){
27869 var d = this.prepareData(records[i].data, i, records[i]);
27871 this.tpl.insertBefore(n, d);
27874 this.tpl.append(this.el, d);
27877 this.updateIndexes(index);
27880 onRemove : function(ds, record, index){
27881 // Roo.log('onRemove');
27882 this.clearSelections();
27883 var el = this.dataName ?
27884 this.el.child('.roo-tpl-' + this.dataName) :
27887 el.dom.removeChild(this.nodes[index]);
27888 this.updateIndexes(index);
27892 * Refresh an individual node.
27893 * @param {Number} index
27895 refreshNode : function(index){
27896 this.onUpdate(this.store, this.store.getAt(index));
27899 updateIndexes : function(startIndex, endIndex){
27900 var ns = this.nodes;
27901 startIndex = startIndex || 0;
27902 endIndex = endIndex || ns.length - 1;
27903 for(var i = startIndex; i <= endIndex; i++){
27904 ns[i].nodeIndex = i;
27909 * Changes the data store this view uses and refresh the view.
27910 * @param {Store} store
27912 setStore : function(store, initial){
27913 if(!initial && this.store){
27914 this.store.un("datachanged", this.refresh);
27915 this.store.un("add", this.onAdd);
27916 this.store.un("remove", this.onRemove);
27917 this.store.un("update", this.onUpdate);
27918 this.store.un("clear", this.refresh);
27919 this.store.un("beforeload", this.onBeforeLoad);
27920 this.store.un("load", this.onLoad);
27921 this.store.un("loadexception", this.onLoad);
27925 store.on("datachanged", this.refresh, this);
27926 store.on("add", this.onAdd, this);
27927 store.on("remove", this.onRemove, this);
27928 store.on("update", this.onUpdate, this);
27929 store.on("clear", this.refresh, this);
27930 store.on("beforeload", this.onBeforeLoad, this);
27931 store.on("load", this.onLoad, this);
27932 store.on("loadexception", this.onLoad, this);
27940 * onbeforeLoad - masks the loading area.
27943 onBeforeLoad : function(store,opts)
27945 //Roo.log('onBeforeLoad');
27947 this.el.update("");
27949 this.el.mask(this.mask ? this.mask : "Loading" );
27951 onLoad : function ()
27958 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27959 * @param {HTMLElement} node
27960 * @return {HTMLElement} The template node
27962 findItemFromChild : function(node){
27963 var el = this.dataName ?
27964 this.el.child('.roo-tpl-' + this.dataName,true) :
27967 if(!node || node.parentNode == el){
27970 var p = node.parentNode;
27971 while(p && p != el){
27972 if(p.parentNode == el){
27981 onClick : function(e){
27982 var item = this.findItemFromChild(e.getTarget());
27984 var index = this.indexOf(item);
27985 if(this.onItemClick(item, index, e) !== false){
27986 this.fireEvent("click", this, index, item, e);
27989 this.clearSelections();
27994 onContextMenu : function(e){
27995 var item = this.findItemFromChild(e.getTarget());
27997 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
28002 onDblClick : function(e){
28003 var item = this.findItemFromChild(e.getTarget());
28005 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
28009 onItemClick : function(item, index, e)
28011 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28014 if (this.toggleSelect) {
28015 var m = this.isSelected(item) ? 'unselect' : 'select';
28018 _t[m](item, true, false);
28021 if(this.multiSelect || this.singleSelect){
28022 if(this.multiSelect && e.shiftKey && this.lastSelection){
28023 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
28025 this.select(item, this.multiSelect && e.ctrlKey);
28026 this.lastSelection = item;
28029 if(!this.tickable){
28030 e.preventDefault();
28038 * Get the number of selected nodes.
28041 getSelectionCount : function(){
28042 return this.selections.length;
28046 * Get the currently selected nodes.
28047 * @return {Array} An array of HTMLElements
28049 getSelectedNodes : function(){
28050 return this.selections;
28054 * Get the indexes of the selected nodes.
28057 getSelectedIndexes : function(){
28058 var indexes = [], s = this.selections;
28059 for(var i = 0, len = s.length; i < len; i++){
28060 indexes.push(s[i].nodeIndex);
28066 * Clear all selections
28067 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
28069 clearSelections : function(suppressEvent){
28070 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
28071 this.cmp.elements = this.selections;
28072 this.cmp.removeClass(this.selectedClass);
28073 this.selections = [];
28074 if(!suppressEvent){
28075 this.fireEvent("selectionchange", this, this.selections);
28081 * Returns true if the passed node is selected
28082 * @param {HTMLElement/Number} node The node or node index
28083 * @return {Boolean}
28085 isSelected : function(node){
28086 var s = this.selections;
28090 node = this.getNode(node);
28091 return s.indexOf(node) !== -1;
28096 * @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
28097 * @param {Boolean} keepExisting (optional) true to keep existing selections
28098 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
28100 select : function(nodeInfo, keepExisting, suppressEvent){
28101 if(nodeInfo instanceof Array){
28103 this.clearSelections(true);
28105 for(var i = 0, len = nodeInfo.length; i < len; i++){
28106 this.select(nodeInfo[i], true, true);
28110 var node = this.getNode(nodeInfo);
28111 if(!node || this.isSelected(node)){
28112 return; // already selected.
28115 this.clearSelections(true);
28118 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28119 Roo.fly(node).addClass(this.selectedClass);
28120 this.selections.push(node);
28121 if(!suppressEvent){
28122 this.fireEvent("selectionchange", this, this.selections);
28130 * @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
28131 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
28132 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
28134 unselect : function(nodeInfo, keepExisting, suppressEvent)
28136 if(nodeInfo instanceof Array){
28137 Roo.each(this.selections, function(s) {
28138 this.unselect(s, nodeInfo);
28142 var node = this.getNode(nodeInfo);
28143 if(!node || !this.isSelected(node)){
28144 //Roo.log("not selected");
28145 return; // not selected.
28149 Roo.each(this.selections, function(s) {
28151 Roo.fly(node).removeClass(this.selectedClass);
28158 this.selections= ns;
28159 this.fireEvent("selectionchange", this, this.selections);
28163 * Gets a template node.
28164 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
28165 * @return {HTMLElement} The node or null if it wasn't found
28167 getNode : function(nodeInfo){
28168 if(typeof nodeInfo == "string"){
28169 return document.getElementById(nodeInfo);
28170 }else if(typeof nodeInfo == "number"){
28171 return this.nodes[nodeInfo];
28177 * Gets a range template nodes.
28178 * @param {Number} startIndex
28179 * @param {Number} endIndex
28180 * @return {Array} An array of nodes
28182 getNodes : function(start, end){
28183 var ns = this.nodes;
28184 start = start || 0;
28185 end = typeof end == "undefined" ? ns.length - 1 : end;
28188 for(var i = start; i <= end; i++){
28192 for(var i = start; i >= end; i--){
28200 * Finds the index of the passed node
28201 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
28202 * @return {Number} The index of the node or -1
28204 indexOf : function(node){
28205 node = this.getNode(node);
28206 if(typeof node.nodeIndex == "number"){
28207 return node.nodeIndex;
28209 var ns = this.nodes;
28210 for(var i = 0, len = ns.length; i < len; i++){
28220 * Ext JS Library 1.1.1
28221 * Copyright(c) 2006-2007, Ext JS, LLC.
28223 * Originally Released Under LGPL - original licence link has changed is not relivant.
28226 * <script type="text/javascript">
28230 * @class Roo.JsonView
28231 * @extends Roo.View
28232 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
28234 var view = new Roo.JsonView({
28235 container: "my-element",
28236 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
28241 // listen for node click?
28242 view.on("click", function(vw, index, node, e){
28243 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
28246 // direct load of JSON data
28247 view.load("foobar.php");
28249 // Example from my blog list
28250 var tpl = new Roo.Template(
28251 '<div class="entry">' +
28252 '<a class="entry-title" href="{link}">{title}</a>' +
28253 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
28254 "</div><hr />"
28257 var moreView = new Roo.JsonView({
28258 container : "entry-list",
28262 moreView.on("beforerender", this.sortEntries, this);
28264 url: "/blog/get-posts.php",
28265 params: "allposts=true",
28266 text: "Loading Blog Entries..."
28270 * Note: old code is supported with arguments : (container, template, config)
28274 * Create a new JsonView
28276 * @param {Object} config The config object
28279 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
28282 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
28284 var um = this.el.getUpdateManager();
28285 um.setRenderer(this);
28286 um.on("update", this.onLoad, this);
28287 um.on("failure", this.onLoadException, this);
28290 * @event beforerender
28291 * Fires before rendering of the downloaded JSON data.
28292 * @param {Roo.JsonView} this
28293 * @param {Object} data The JSON data loaded
28297 * Fires when data is loaded.
28298 * @param {Roo.JsonView} this
28299 * @param {Object} data The JSON data loaded
28300 * @param {Object} response The raw Connect response object
28303 * @event loadexception
28304 * Fires when loading fails.
28305 * @param {Roo.JsonView} this
28306 * @param {Object} response The raw Connect response object
28309 'beforerender' : true,
28311 'loadexception' : true
28314 Roo.extend(Roo.JsonView, Roo.View, {
28316 * @type {String} The root property in the loaded JSON object that contains the data
28321 * Refreshes the view.
28323 refresh : function(){
28324 this.clearSelections();
28325 this.el.update("");
28327 var o = this.jsonData;
28328 if(o && o.length > 0){
28329 for(var i = 0, len = o.length; i < len; i++){
28330 var data = this.prepareData(o[i], i, o);
28331 html[html.length] = this.tpl.apply(data);
28334 html.push(this.emptyText);
28336 this.el.update(html.join(""));
28337 this.nodes = this.el.dom.childNodes;
28338 this.updateIndexes(0);
28342 * 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.
28343 * @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:
28346 url: "your-url.php",
28347 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
28348 callback: yourFunction,
28349 scope: yourObject, //(optional scope)
28352 text: "Loading...",
28357 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
28358 * 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.
28359 * @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}
28360 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
28361 * @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.
28364 var um = this.el.getUpdateManager();
28365 um.update.apply(um, arguments);
28368 // note - render is a standard framework call...
28369 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
28370 render : function(el, response){
28372 this.clearSelections();
28373 this.el.update("");
28376 if (response != '') {
28377 o = Roo.util.JSON.decode(response.responseText);
28380 o = o[this.jsonRoot];
28386 * The current JSON data or null
28389 this.beforeRender();
28394 * Get the number of records in the current JSON dataset
28397 getCount : function(){
28398 return this.jsonData ? this.jsonData.length : 0;
28402 * Returns the JSON object for the specified node(s)
28403 * @param {HTMLElement/Array} node The node or an array of nodes
28404 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
28405 * you get the JSON object for the node
28407 getNodeData : function(node){
28408 if(node instanceof Array){
28410 for(var i = 0, len = node.length; i < len; i++){
28411 data.push(this.getNodeData(node[i]));
28415 return this.jsonData[this.indexOf(node)] || null;
28418 beforeRender : function(){
28419 this.snapshot = this.jsonData;
28421 this.sort.apply(this, this.sortInfo);
28423 this.fireEvent("beforerender", this, this.jsonData);
28426 onLoad : function(el, o){
28427 this.fireEvent("load", this, this.jsonData, o);
28430 onLoadException : function(el, o){
28431 this.fireEvent("loadexception", this, o);
28435 * Filter the data by a specific property.
28436 * @param {String} property A property on your JSON objects
28437 * @param {String/RegExp} value Either string that the property values
28438 * should start with, or a RegExp to test against the property
28440 filter : function(property, value){
28443 var ss = this.snapshot;
28444 if(typeof value == "string"){
28445 var vlen = value.length;
28447 this.clearFilter();
28450 value = value.toLowerCase();
28451 for(var i = 0, len = ss.length; i < len; i++){
28453 if(o[property].substr(0, vlen).toLowerCase() == value){
28457 } else if(value.exec){ // regex?
28458 for(var i = 0, len = ss.length; i < len; i++){
28460 if(value.test(o[property])){
28467 this.jsonData = data;
28473 * Filter by a function. The passed function will be called with each
28474 * object in the current dataset. If the function returns true the value is kept,
28475 * otherwise it is filtered.
28476 * @param {Function} fn
28477 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
28479 filterBy : function(fn, scope){
28482 var ss = this.snapshot;
28483 for(var i = 0, len = ss.length; i < len; i++){
28485 if(fn.call(scope || this, o)){
28489 this.jsonData = data;
28495 * Clears the current filter.
28497 clearFilter : function(){
28498 if(this.snapshot && this.jsonData != this.snapshot){
28499 this.jsonData = this.snapshot;
28506 * Sorts the data for this view and refreshes it.
28507 * @param {String} property A property on your JSON objects to sort on
28508 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
28509 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
28511 sort : function(property, dir, sortType){
28512 this.sortInfo = Array.prototype.slice.call(arguments, 0);
28515 var dsc = dir && dir.toLowerCase() == "desc";
28516 var f = function(o1, o2){
28517 var v1 = sortType ? sortType(o1[p]) : o1[p];
28518 var v2 = sortType ? sortType(o2[p]) : o2[p];
28521 return dsc ? +1 : -1;
28522 } else if(v1 > v2){
28523 return dsc ? -1 : +1;
28528 this.jsonData.sort(f);
28530 if(this.jsonData != this.snapshot){
28531 this.snapshot.sort(f);
28537 * Ext JS Library 1.1.1
28538 * Copyright(c) 2006-2007, Ext JS, LLC.
28540 * Originally Released Under LGPL - original licence link has changed is not relivant.
28543 * <script type="text/javascript">
28548 * @class Roo.ColorPalette
28549 * @extends Roo.Component
28550 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
28551 * Here's an example of typical usage:
28553 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
28554 cp.render('my-div');
28556 cp.on('select', function(palette, selColor){
28557 // do something with selColor
28561 * Create a new ColorPalette
28562 * @param {Object} config The config object
28564 Roo.ColorPalette = function(config){
28565 Roo.ColorPalette.superclass.constructor.call(this, config);
28569 * Fires when a color is selected
28570 * @param {ColorPalette} this
28571 * @param {String} color The 6-digit color hex code (without the # symbol)
28577 this.on("select", this.handler, this.scope, true);
28580 Roo.extend(Roo.ColorPalette, Roo.Component, {
28582 * @cfg {String} itemCls
28583 * The CSS class to apply to the containing element (defaults to "x-color-palette")
28585 itemCls : "x-color-palette",
28587 * @cfg {String} value
28588 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
28589 * the hex codes are case-sensitive.
28592 clickEvent:'click',
28594 ctype: "Roo.ColorPalette",
28597 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
28599 allowReselect : false,
28602 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
28603 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
28604 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
28605 * of colors with the width setting until the box is symmetrical.</p>
28606 * <p>You can override individual colors if needed:</p>
28608 var cp = new Roo.ColorPalette();
28609 cp.colors[0] = "FF0000"; // change the first box to red
28612 Or you can provide a custom array of your own for complete control:
28614 var cp = new Roo.ColorPalette();
28615 cp.colors = ["000000", "993300", "333300"];
28620 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
28621 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
28622 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
28623 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
28624 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
28628 onRender : function(container, position){
28629 var t = new Roo.MasterTemplate(
28630 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
28632 var c = this.colors;
28633 for(var i = 0, len = c.length; i < len; i++){
28636 var el = document.createElement("div");
28637 el.className = this.itemCls;
28639 container.dom.insertBefore(el, position);
28640 this.el = Roo.get(el);
28641 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
28642 if(this.clickEvent != 'click'){
28643 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
28648 afterRender : function(){
28649 Roo.ColorPalette.superclass.afterRender.call(this);
28651 var s = this.value;
28658 handleClick : function(e, t){
28659 e.preventDefault();
28660 if(!this.disabled){
28661 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
28662 this.select(c.toUpperCase());
28667 * Selects the specified color in the palette (fires the select event)
28668 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
28670 select : function(color){
28671 color = color.replace("#", "");
28672 if(color != this.value || this.allowReselect){
28675 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
28677 el.child("a.color-"+color).addClass("x-color-palette-sel");
28678 this.value = color;
28679 this.fireEvent("select", this, color);
28684 * Ext JS Library 1.1.1
28685 * Copyright(c) 2006-2007, Ext JS, LLC.
28687 * Originally Released Under LGPL - original licence link has changed is not relivant.
28690 * <script type="text/javascript">
28694 * @class Roo.DatePicker
28695 * @extends Roo.Component
28696 * Simple date picker class.
28698 * Create a new DatePicker
28699 * @param {Object} config The config object
28701 Roo.DatePicker = function(config){
28702 Roo.DatePicker.superclass.constructor.call(this, config);
28704 this.value = config && config.value ?
28705 config.value.clearTime() : new Date().clearTime();
28710 * Fires when a date is selected
28711 * @param {DatePicker} this
28712 * @param {Date} date The selected date
28716 * @event monthchange
28717 * Fires when the displayed month changes
28718 * @param {DatePicker} this
28719 * @param {Date} date The selected month
28721 'monthchange': true
28725 this.on("select", this.handler, this.scope || this);
28727 // build the disabledDatesRE
28728 if(!this.disabledDatesRE && this.disabledDates){
28729 var dd = this.disabledDates;
28731 for(var i = 0; i < dd.length; i++){
28733 if(i != dd.length-1) {
28737 this.disabledDatesRE = new RegExp(re + ")");
28741 Roo.extend(Roo.DatePicker, Roo.Component, {
28743 * @cfg {String} todayText
28744 * The text to display on the button that selects the current date (defaults to "Today")
28746 todayText : "Today",
28748 * @cfg {String} okText
28749 * The text to display on the ok button
28751 okText : " OK ", //   to give the user extra clicking room
28753 * @cfg {String} cancelText
28754 * The text to display on the cancel button
28756 cancelText : "Cancel",
28758 * @cfg {String} todayTip
28759 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
28761 todayTip : "{0} (Spacebar)",
28763 * @cfg {Date} minDate
28764 * Minimum allowable date (JavaScript date object, defaults to null)
28768 * @cfg {Date} maxDate
28769 * Maximum allowable date (JavaScript date object, defaults to null)
28773 * @cfg {String} minText
28774 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
28776 minText : "This date is before the minimum date",
28778 * @cfg {String} maxText
28779 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
28781 maxText : "This date is after the maximum date",
28783 * @cfg {String} format
28784 * The default date format string which can be overriden for localization support. The format must be
28785 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
28789 * @cfg {Array} disabledDays
28790 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
28792 disabledDays : null,
28794 * @cfg {String} disabledDaysText
28795 * The tooltip to display when the date falls on a disabled day (defaults to "")
28797 disabledDaysText : "",
28799 * @cfg {RegExp} disabledDatesRE
28800 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
28802 disabledDatesRE : null,
28804 * @cfg {String} disabledDatesText
28805 * The tooltip text to display when the date falls on a disabled date (defaults to "")
28807 disabledDatesText : "",
28809 * @cfg {Boolean} constrainToViewport
28810 * True to constrain the date picker to the viewport (defaults to true)
28812 constrainToViewport : true,
28814 * @cfg {Array} monthNames
28815 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
28817 monthNames : Date.monthNames,
28819 * @cfg {Array} dayNames
28820 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
28822 dayNames : Date.dayNames,
28824 * @cfg {String} nextText
28825 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
28827 nextText: 'Next Month (Control+Right)',
28829 * @cfg {String} prevText
28830 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
28832 prevText: 'Previous Month (Control+Left)',
28834 * @cfg {String} monthYearText
28835 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
28837 monthYearText: 'Choose a month (Control+Up/Down to move years)',
28839 * @cfg {Number} startDay
28840 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
28844 * @cfg {Bool} showClear
28845 * Show a clear button (usefull for date form elements that can be blank.)
28851 * Sets the value of the date field
28852 * @param {Date} value The date to set
28854 setValue : function(value){
28855 var old = this.value;
28857 if (typeof(value) == 'string') {
28859 value = Date.parseDate(value, this.format);
28862 value = new Date();
28865 this.value = value.clearTime(true);
28867 this.update(this.value);
28872 * Gets the current selected value of the date field
28873 * @return {Date} The selected date
28875 getValue : function(){
28880 focus : function(){
28882 this.update(this.activeDate);
28887 onRender : function(container, position){
28890 '<table cellspacing="0">',
28891 '<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>',
28892 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28893 var dn = this.dayNames;
28894 for(var i = 0; i < 7; i++){
28895 var d = this.startDay+i;
28899 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28901 m[m.length] = "</tr></thead><tbody><tr>";
28902 for(var i = 0; i < 42; i++) {
28903 if(i % 7 == 0 && i != 0){
28904 m[m.length] = "</tr><tr>";
28906 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28908 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28909 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28911 var el = document.createElement("div");
28912 el.className = "x-date-picker";
28913 el.innerHTML = m.join("");
28915 container.dom.insertBefore(el, position);
28917 this.el = Roo.get(el);
28918 this.eventEl = Roo.get(el.firstChild);
28920 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28921 handler: this.showPrevMonth,
28923 preventDefault:true,
28927 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28928 handler: this.showNextMonth,
28930 preventDefault:true,
28934 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28936 this.monthPicker = this.el.down('div.x-date-mp');
28937 this.monthPicker.enableDisplayMode('block');
28939 var kn = new Roo.KeyNav(this.eventEl, {
28940 "left" : function(e){
28942 this.showPrevMonth() :
28943 this.update(this.activeDate.add("d", -1));
28946 "right" : function(e){
28948 this.showNextMonth() :
28949 this.update(this.activeDate.add("d", 1));
28952 "up" : function(e){
28954 this.showNextYear() :
28955 this.update(this.activeDate.add("d", -7));
28958 "down" : function(e){
28960 this.showPrevYear() :
28961 this.update(this.activeDate.add("d", 7));
28964 "pageUp" : function(e){
28965 this.showNextMonth();
28968 "pageDown" : function(e){
28969 this.showPrevMonth();
28972 "enter" : function(e){
28973 e.stopPropagation();
28980 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28982 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28984 this.el.unselectable();
28986 this.cells = this.el.select("table.x-date-inner tbody td");
28987 this.textNodes = this.el.query("table.x-date-inner tbody span");
28989 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28991 tooltip: this.monthYearText
28994 this.mbtn.on('click', this.showMonthPicker, this);
28995 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28998 var today = (new Date()).dateFormat(this.format);
29000 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
29001 if (this.showClear) {
29002 baseTb.add( new Roo.Toolbar.Fill());
29005 text: String.format(this.todayText, today),
29006 tooltip: String.format(this.todayTip, today),
29007 handler: this.selectToday,
29011 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
29014 if (this.showClear) {
29016 baseTb.add( new Roo.Toolbar.Fill());
29019 cls: 'x-btn-icon x-btn-clear',
29020 handler: function() {
29022 this.fireEvent("select", this, '');
29032 this.update(this.value);
29035 createMonthPicker : function(){
29036 if(!this.monthPicker.dom.firstChild){
29037 var buf = ['<table border="0" cellspacing="0">'];
29038 for(var i = 0; i < 6; i++){
29040 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
29041 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
29043 '<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>' :
29044 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
29048 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
29050 '</button><button type="button" class="x-date-mp-cancel">',
29052 '</button></td></tr>',
29055 this.monthPicker.update(buf.join(''));
29056 this.monthPicker.on('click', this.onMonthClick, this);
29057 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
29059 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
29060 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
29062 this.mpMonths.each(function(m, a, i){
29065 m.dom.xmonth = 5 + Math.round(i * .5);
29067 m.dom.xmonth = Math.round((i-1) * .5);
29073 showMonthPicker : function(){
29074 this.createMonthPicker();
29075 var size = this.el.getSize();
29076 this.monthPicker.setSize(size);
29077 this.monthPicker.child('table').setSize(size);
29079 this.mpSelMonth = (this.activeDate || this.value).getMonth();
29080 this.updateMPMonth(this.mpSelMonth);
29081 this.mpSelYear = (this.activeDate || this.value).getFullYear();
29082 this.updateMPYear(this.mpSelYear);
29084 this.monthPicker.slideIn('t', {duration:.2});
29087 updateMPYear : function(y){
29089 var ys = this.mpYears.elements;
29090 for(var i = 1; i <= 10; i++){
29091 var td = ys[i-1], y2;
29093 y2 = y + Math.round(i * .5);
29094 td.firstChild.innerHTML = y2;
29097 y2 = y - (5-Math.round(i * .5));
29098 td.firstChild.innerHTML = y2;
29101 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
29105 updateMPMonth : function(sm){
29106 this.mpMonths.each(function(m, a, i){
29107 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
29111 selectMPMonth: function(m){
29115 onMonthClick : function(e, t){
29117 var el = new Roo.Element(t), pn;
29118 if(el.is('button.x-date-mp-cancel')){
29119 this.hideMonthPicker();
29121 else if(el.is('button.x-date-mp-ok')){
29122 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
29123 this.hideMonthPicker();
29125 else if(pn = el.up('td.x-date-mp-month', 2)){
29126 this.mpMonths.removeClass('x-date-mp-sel');
29127 pn.addClass('x-date-mp-sel');
29128 this.mpSelMonth = pn.dom.xmonth;
29130 else if(pn = el.up('td.x-date-mp-year', 2)){
29131 this.mpYears.removeClass('x-date-mp-sel');
29132 pn.addClass('x-date-mp-sel');
29133 this.mpSelYear = pn.dom.xyear;
29135 else if(el.is('a.x-date-mp-prev')){
29136 this.updateMPYear(this.mpyear-10);
29138 else if(el.is('a.x-date-mp-next')){
29139 this.updateMPYear(this.mpyear+10);
29143 onMonthDblClick : function(e, t){
29145 var el = new Roo.Element(t), pn;
29146 if(pn = el.up('td.x-date-mp-month', 2)){
29147 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
29148 this.hideMonthPicker();
29150 else if(pn = el.up('td.x-date-mp-year', 2)){
29151 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
29152 this.hideMonthPicker();
29156 hideMonthPicker : function(disableAnim){
29157 if(this.monthPicker){
29158 if(disableAnim === true){
29159 this.monthPicker.hide();
29161 this.monthPicker.slideOut('t', {duration:.2});
29167 showPrevMonth : function(e){
29168 this.update(this.activeDate.add("mo", -1));
29172 showNextMonth : function(e){
29173 this.update(this.activeDate.add("mo", 1));
29177 showPrevYear : function(){
29178 this.update(this.activeDate.add("y", -1));
29182 showNextYear : function(){
29183 this.update(this.activeDate.add("y", 1));
29187 handleMouseWheel : function(e){
29188 var delta = e.getWheelDelta();
29190 this.showPrevMonth();
29192 } else if(delta < 0){
29193 this.showNextMonth();
29199 handleDateClick : function(e, t){
29201 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
29202 this.setValue(new Date(t.dateValue));
29203 this.fireEvent("select", this, this.value);
29208 selectToday : function(){
29209 this.setValue(new Date().clearTime());
29210 this.fireEvent("select", this, this.value);
29214 update : function(date)
29216 var vd = this.activeDate;
29217 this.activeDate = date;
29219 var t = date.getTime();
29220 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
29221 this.cells.removeClass("x-date-selected");
29222 this.cells.each(function(c){
29223 if(c.dom.firstChild.dateValue == t){
29224 c.addClass("x-date-selected");
29225 setTimeout(function(){
29226 try{c.dom.firstChild.focus();}catch(e){}
29235 var days = date.getDaysInMonth();
29236 var firstOfMonth = date.getFirstDateOfMonth();
29237 var startingPos = firstOfMonth.getDay()-this.startDay;
29239 if(startingPos <= this.startDay){
29243 var pm = date.add("mo", -1);
29244 var prevStart = pm.getDaysInMonth()-startingPos;
29246 var cells = this.cells.elements;
29247 var textEls = this.textNodes;
29248 days += startingPos;
29250 // convert everything to numbers so it's fast
29251 var day = 86400000;
29252 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
29253 var today = new Date().clearTime().getTime();
29254 var sel = date.clearTime().getTime();
29255 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
29256 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
29257 var ddMatch = this.disabledDatesRE;
29258 var ddText = this.disabledDatesText;
29259 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
29260 var ddaysText = this.disabledDaysText;
29261 var format = this.format;
29263 var setCellClass = function(cal, cell){
29265 var t = d.getTime();
29266 cell.firstChild.dateValue = t;
29268 cell.className += " x-date-today";
29269 cell.title = cal.todayText;
29272 cell.className += " x-date-selected";
29273 setTimeout(function(){
29274 try{cell.firstChild.focus();}catch(e){}
29279 cell.className = " x-date-disabled";
29280 cell.title = cal.minText;
29284 cell.className = " x-date-disabled";
29285 cell.title = cal.maxText;
29289 if(ddays.indexOf(d.getDay()) != -1){
29290 cell.title = ddaysText;
29291 cell.className = " x-date-disabled";
29294 if(ddMatch && format){
29295 var fvalue = d.dateFormat(format);
29296 if(ddMatch.test(fvalue)){
29297 cell.title = ddText.replace("%0", fvalue);
29298 cell.className = " x-date-disabled";
29304 for(; i < startingPos; i++) {
29305 textEls[i].innerHTML = (++prevStart);
29306 d.setDate(d.getDate()+1);
29307 cells[i].className = "x-date-prevday";
29308 setCellClass(this, cells[i]);
29310 for(; i < days; i++){
29311 intDay = i - startingPos + 1;
29312 textEls[i].innerHTML = (intDay);
29313 d.setDate(d.getDate()+1);
29314 cells[i].className = "x-date-active";
29315 setCellClass(this, cells[i]);
29318 for(; i < 42; i++) {
29319 textEls[i].innerHTML = (++extraDays);
29320 d.setDate(d.getDate()+1);
29321 cells[i].className = "x-date-nextday";
29322 setCellClass(this, cells[i]);
29325 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
29326 this.fireEvent('monthchange', this, date);
29328 if(!this.internalRender){
29329 var main = this.el.dom.firstChild;
29330 var w = main.offsetWidth;
29331 this.el.setWidth(w + this.el.getBorderWidth("lr"));
29332 Roo.fly(main).setWidth(w);
29333 this.internalRender = true;
29334 // opera does not respect the auto grow header center column
29335 // then, after it gets a width opera refuses to recalculate
29336 // without a second pass
29337 if(Roo.isOpera && !this.secondPass){
29338 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
29339 this.secondPass = true;
29340 this.update.defer(10, this, [date]);
29348 * Ext JS Library 1.1.1
29349 * Copyright(c) 2006-2007, Ext JS, LLC.
29351 * Originally Released Under LGPL - original licence link has changed is not relivant.
29354 * <script type="text/javascript">
29357 * @class Roo.TabPanel
29358 * @extends Roo.util.Observable
29359 * A lightweight tab container.
29363 // basic tabs 1, built from existing content
29364 var tabs = new Roo.TabPanel("tabs1");
29365 tabs.addTab("script", "View Script");
29366 tabs.addTab("markup", "View Markup");
29367 tabs.activate("script");
29369 // more advanced tabs, built from javascript
29370 var jtabs = new Roo.TabPanel("jtabs");
29371 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
29373 // set up the UpdateManager
29374 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
29375 var updater = tab2.getUpdateManager();
29376 updater.setDefaultUrl("ajax1.htm");
29377 tab2.on('activate', updater.refresh, updater, true);
29379 // Use setUrl for Ajax loading
29380 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
29381 tab3.setUrl("ajax2.htm", null, true);
29384 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
29387 jtabs.activate("jtabs-1");
29390 * Create a new TabPanel.
29391 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
29392 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
29394 Roo.TabPanel = function(container, config){
29396 * The container element for this TabPanel.
29397 * @type Roo.Element
29399 this.el = Roo.get(container, true);
29401 if(typeof config == "boolean"){
29402 this.tabPosition = config ? "bottom" : "top";
29404 Roo.apply(this, config);
29407 if(this.tabPosition == "bottom"){
29408 this.bodyEl = Roo.get(this.createBody(this.el.dom));
29409 this.el.addClass("x-tabs-bottom");
29411 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
29412 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
29413 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
29415 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
29417 if(this.tabPosition != "bottom"){
29418 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
29419 * @type Roo.Element
29421 this.bodyEl = Roo.get(this.createBody(this.el.dom));
29422 this.el.addClass("x-tabs-top");
29426 this.bodyEl.setStyle("position", "relative");
29428 this.active = null;
29429 this.activateDelegate = this.activate.createDelegate(this);
29434 * Fires when the active tab changes
29435 * @param {Roo.TabPanel} this
29436 * @param {Roo.TabPanelItem} activePanel The new active tab
29440 * @event beforetabchange
29441 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
29442 * @param {Roo.TabPanel} this
29443 * @param {Object} e Set cancel to true on this object to cancel the tab change
29444 * @param {Roo.TabPanelItem} tab The tab being changed to
29446 "beforetabchange" : true
29449 Roo.EventManager.onWindowResize(this.onResize, this);
29450 this.cpad = this.el.getPadding("lr");
29451 this.hiddenCount = 0;
29454 // toolbar on the tabbar support...
29455 if (this.toolbar) {
29456 var tcfg = this.toolbar;
29457 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
29458 this.toolbar = new Roo.Toolbar(tcfg);
29459 if (Roo.isSafari) {
29460 var tbl = tcfg.container.child('table', true);
29461 tbl.setAttribute('width', '100%');
29468 Roo.TabPanel.superclass.constructor.call(this);
29471 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
29473 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
29475 tabPosition : "top",
29477 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
29479 currentTabWidth : 0,
29481 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
29485 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
29489 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
29491 preferredTabWidth : 175,
29493 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
29495 resizeTabs : false,
29497 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
29499 monitorResize : true,
29501 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
29506 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
29507 * @param {String} id The id of the div to use <b>or create</b>
29508 * @param {String} text The text for the tab
29509 * @param {String} content (optional) Content to put in the TabPanelItem body
29510 * @param {Boolean} closable (optional) True to create a close icon on the tab
29511 * @return {Roo.TabPanelItem} The created TabPanelItem
29513 addTab : function(id, text, content, closable){
29514 var item = new Roo.TabPanelItem(this, id, text, closable);
29515 this.addTabItem(item);
29517 item.setContent(content);
29523 * Returns the {@link Roo.TabPanelItem} with the specified id/index
29524 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
29525 * @return {Roo.TabPanelItem}
29527 getTab : function(id){
29528 return this.items[id];
29532 * Hides the {@link Roo.TabPanelItem} with the specified id/index
29533 * @param {String/Number} id The id or index of the TabPanelItem to hide.
29535 hideTab : function(id){
29536 var t = this.items[id];
29539 this.hiddenCount++;
29540 this.autoSizeTabs();
29545 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
29546 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
29548 unhideTab : function(id){
29549 var t = this.items[id];
29551 t.setHidden(false);
29552 this.hiddenCount--;
29553 this.autoSizeTabs();
29558 * Adds an existing {@link Roo.TabPanelItem}.
29559 * @param {Roo.TabPanelItem} item The TabPanelItem to add
29561 addTabItem : function(item){
29562 this.items[item.id] = item;
29563 this.items.push(item);
29564 if(this.resizeTabs){
29565 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
29566 this.autoSizeTabs();
29573 * Removes a {@link Roo.TabPanelItem}.
29574 * @param {String/Number} id The id or index of the TabPanelItem to remove.
29576 removeTab : function(id){
29577 var items = this.items;
29578 var tab = items[id];
29579 if(!tab) { return; }
29580 var index = items.indexOf(tab);
29581 if(this.active == tab && items.length > 1){
29582 var newTab = this.getNextAvailable(index);
29587 this.stripEl.dom.removeChild(tab.pnode.dom);
29588 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
29589 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
29591 items.splice(index, 1);
29592 delete this.items[tab.id];
29593 tab.fireEvent("close", tab);
29594 tab.purgeListeners();
29595 this.autoSizeTabs();
29598 getNextAvailable : function(start){
29599 var items = this.items;
29601 // look for a next tab that will slide over to
29602 // replace the one being removed
29603 while(index < items.length){
29604 var item = items[++index];
29605 if(item && !item.isHidden()){
29609 // if one isn't found select the previous tab (on the left)
29612 var item = items[--index];
29613 if(item && !item.isHidden()){
29621 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
29622 * @param {String/Number} id The id or index of the TabPanelItem to disable.
29624 disableTab : function(id){
29625 var tab = this.items[id];
29626 if(tab && this.active != tab){
29632 * Enables a {@link Roo.TabPanelItem} that is disabled.
29633 * @param {String/Number} id The id or index of the TabPanelItem to enable.
29635 enableTab : function(id){
29636 var tab = this.items[id];
29641 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
29642 * @param {String/Number} id The id or index of the TabPanelItem to activate.
29643 * @return {Roo.TabPanelItem} The TabPanelItem.
29645 activate : function(id){
29646 var tab = this.items[id];
29650 if(tab == this.active || tab.disabled){
29654 this.fireEvent("beforetabchange", this, e, tab);
29655 if(e.cancel !== true && !tab.disabled){
29657 this.active.hide();
29659 this.active = this.items[id];
29660 this.active.show();
29661 this.fireEvent("tabchange", this, this.active);
29667 * Gets the active {@link Roo.TabPanelItem}.
29668 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
29670 getActiveTab : function(){
29671 return this.active;
29675 * Updates the tab body element to fit the height of the container element
29676 * for overflow scrolling
29677 * @param {Number} targetHeight (optional) Override the starting height from the elements height
29679 syncHeight : function(targetHeight){
29680 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
29681 var bm = this.bodyEl.getMargins();
29682 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
29683 this.bodyEl.setHeight(newHeight);
29687 onResize : function(){
29688 if(this.monitorResize){
29689 this.autoSizeTabs();
29694 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
29696 beginUpdate : function(){
29697 this.updating = true;
29701 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
29703 endUpdate : function(){
29704 this.updating = false;
29705 this.autoSizeTabs();
29709 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
29711 autoSizeTabs : function(){
29712 var count = this.items.length;
29713 var vcount = count - this.hiddenCount;
29714 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
29717 var w = Math.max(this.el.getWidth() - this.cpad, 10);
29718 var availWidth = Math.floor(w / vcount);
29719 var b = this.stripBody;
29720 if(b.getWidth() > w){
29721 var tabs = this.items;
29722 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
29723 if(availWidth < this.minTabWidth){
29724 /*if(!this.sleft){ // incomplete scrolling code
29725 this.createScrollButtons();
29728 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
29731 if(this.currentTabWidth < this.preferredTabWidth){
29732 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
29738 * Returns the number of tabs in this TabPanel.
29741 getCount : function(){
29742 return this.items.length;
29746 * Resizes all the tabs to the passed width
29747 * @param {Number} The new width
29749 setTabWidth : function(width){
29750 this.currentTabWidth = width;
29751 for(var i = 0, len = this.items.length; i < len; i++) {
29752 if(!this.items[i].isHidden()) {
29753 this.items[i].setWidth(width);
29759 * Destroys this TabPanel
29760 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
29762 destroy : function(removeEl){
29763 Roo.EventManager.removeResizeListener(this.onResize, this);
29764 for(var i = 0, len = this.items.length; i < len; i++){
29765 this.items[i].purgeListeners();
29767 if(removeEl === true){
29768 this.el.update("");
29775 * @class Roo.TabPanelItem
29776 * @extends Roo.util.Observable
29777 * Represents an individual item (tab plus body) in a TabPanel.
29778 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
29779 * @param {String} id The id of this TabPanelItem
29780 * @param {String} text The text for the tab of this TabPanelItem
29781 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
29783 Roo.TabPanelItem = function(tabPanel, id, text, closable){
29785 * The {@link Roo.TabPanel} this TabPanelItem belongs to
29786 * @type Roo.TabPanel
29788 this.tabPanel = tabPanel;
29790 * The id for this TabPanelItem
29795 this.disabled = false;
29799 this.loaded = false;
29800 this.closable = closable;
29803 * The body element for this TabPanelItem.
29804 * @type Roo.Element
29806 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
29807 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
29808 this.bodyEl.setStyle("display", "block");
29809 this.bodyEl.setStyle("zoom", "1");
29812 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
29814 this.el = Roo.get(els.el, true);
29815 this.inner = Roo.get(els.inner, true);
29816 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
29817 this.pnode = Roo.get(els.el.parentNode, true);
29818 this.el.on("mousedown", this.onTabMouseDown, this);
29819 this.el.on("click", this.onTabClick, this);
29822 var c = Roo.get(els.close, true);
29823 c.dom.title = this.closeText;
29824 c.addClassOnOver("close-over");
29825 c.on("click", this.closeClick, this);
29831 * Fires when this tab becomes the active tab.
29832 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29833 * @param {Roo.TabPanelItem} this
29837 * @event beforeclose
29838 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
29839 * @param {Roo.TabPanelItem} this
29840 * @param {Object} e Set cancel to true on this object to cancel the close.
29842 "beforeclose": true,
29845 * Fires when this tab is closed.
29846 * @param {Roo.TabPanelItem} this
29850 * @event deactivate
29851 * Fires when this tab is no longer the active tab.
29852 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29853 * @param {Roo.TabPanelItem} this
29855 "deactivate" : true
29857 this.hidden = false;
29859 Roo.TabPanelItem.superclass.constructor.call(this);
29862 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
29863 purgeListeners : function(){
29864 Roo.util.Observable.prototype.purgeListeners.call(this);
29865 this.el.removeAllListeners();
29868 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
29871 this.pnode.addClass("on");
29874 this.tabPanel.stripWrap.repaint();
29876 this.fireEvent("activate", this.tabPanel, this);
29880 * Returns true if this tab is the active tab.
29881 * @return {Boolean}
29883 isActive : function(){
29884 return this.tabPanel.getActiveTab() == this;
29888 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29891 this.pnode.removeClass("on");
29893 this.fireEvent("deactivate", this.tabPanel, this);
29896 hideAction : function(){
29897 this.bodyEl.hide();
29898 this.bodyEl.setStyle("position", "absolute");
29899 this.bodyEl.setLeft("-20000px");
29900 this.bodyEl.setTop("-20000px");
29903 showAction : function(){
29904 this.bodyEl.setStyle("position", "relative");
29905 this.bodyEl.setTop("");
29906 this.bodyEl.setLeft("");
29907 this.bodyEl.show();
29911 * Set the tooltip for the tab.
29912 * @param {String} tooltip The tab's tooltip
29914 setTooltip : function(text){
29915 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29916 this.textEl.dom.qtip = text;
29917 this.textEl.dom.removeAttribute('title');
29919 this.textEl.dom.title = text;
29923 onTabClick : function(e){
29924 e.preventDefault();
29925 this.tabPanel.activate(this.id);
29928 onTabMouseDown : function(e){
29929 e.preventDefault();
29930 this.tabPanel.activate(this.id);
29933 getWidth : function(){
29934 return this.inner.getWidth();
29937 setWidth : function(width){
29938 var iwidth = width - this.pnode.getPadding("lr");
29939 this.inner.setWidth(iwidth);
29940 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29941 this.pnode.setWidth(width);
29945 * Show or hide the tab
29946 * @param {Boolean} hidden True to hide or false to show.
29948 setHidden : function(hidden){
29949 this.hidden = hidden;
29950 this.pnode.setStyle("display", hidden ? "none" : "");
29954 * Returns true if this tab is "hidden"
29955 * @return {Boolean}
29957 isHidden : function(){
29958 return this.hidden;
29962 * Returns the text for this tab
29965 getText : function(){
29969 autoSize : function(){
29970 //this.el.beginMeasure();
29971 this.textEl.setWidth(1);
29973 * #2804 [new] Tabs in Roojs
29974 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29976 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29977 //this.el.endMeasure();
29981 * Sets the text for the tab (Note: this also sets the tooltip text)
29982 * @param {String} text The tab's text and tooltip
29984 setText : function(text){
29986 this.textEl.update(text);
29987 this.setTooltip(text);
29988 if(!this.tabPanel.resizeTabs){
29993 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29995 activate : function(){
29996 this.tabPanel.activate(this.id);
30000 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
30002 disable : function(){
30003 if(this.tabPanel.active != this){
30004 this.disabled = true;
30005 this.pnode.addClass("disabled");
30010 * Enables this TabPanelItem if it was previously disabled.
30012 enable : function(){
30013 this.disabled = false;
30014 this.pnode.removeClass("disabled");
30018 * Sets the content for this TabPanelItem.
30019 * @param {String} content The content
30020 * @param {Boolean} loadScripts true to look for and load scripts
30022 setContent : function(content, loadScripts){
30023 this.bodyEl.update(content, loadScripts);
30027 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
30028 * @return {Roo.UpdateManager} The UpdateManager
30030 getUpdateManager : function(){
30031 return this.bodyEl.getUpdateManager();
30035 * Set a URL to be used to load the content for this TabPanelItem.
30036 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
30037 * @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)
30038 * @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)
30039 * @return {Roo.UpdateManager} The UpdateManager
30041 setUrl : function(url, params, loadOnce){
30042 if(this.refreshDelegate){
30043 this.un('activate', this.refreshDelegate);
30045 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
30046 this.on("activate", this.refreshDelegate);
30047 return this.bodyEl.getUpdateManager();
30051 _handleRefresh : function(url, params, loadOnce){
30052 if(!loadOnce || !this.loaded){
30053 var updater = this.bodyEl.getUpdateManager();
30054 updater.update(url, params, this._setLoaded.createDelegate(this));
30059 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
30060 * Will fail silently if the setUrl method has not been called.
30061 * This does not activate the panel, just updates its content.
30063 refresh : function(){
30064 if(this.refreshDelegate){
30065 this.loaded = false;
30066 this.refreshDelegate();
30071 _setLoaded : function(){
30072 this.loaded = true;
30076 closeClick : function(e){
30079 this.fireEvent("beforeclose", this, o);
30080 if(o.cancel !== true){
30081 this.tabPanel.removeTab(this.id);
30085 * The text displayed in the tooltip for the close icon.
30088 closeText : "Close this tab"
30092 Roo.TabPanel.prototype.createStrip = function(container){
30093 var strip = document.createElement("div");
30094 strip.className = "x-tabs-wrap";
30095 container.appendChild(strip);
30099 Roo.TabPanel.prototype.createStripList = function(strip){
30100 // div wrapper for retard IE
30101 // returns the "tr" element.
30102 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
30103 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
30104 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
30105 return strip.firstChild.firstChild.firstChild.firstChild;
30108 Roo.TabPanel.prototype.createBody = function(container){
30109 var body = document.createElement("div");
30110 Roo.id(body, "tab-body");
30111 Roo.fly(body).addClass("x-tabs-body");
30112 container.appendChild(body);
30116 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
30117 var body = Roo.getDom(id);
30119 body = document.createElement("div");
30122 Roo.fly(body).addClass("x-tabs-item-body");
30123 bodyEl.insertBefore(body, bodyEl.firstChild);
30127 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
30128 var td = document.createElement("td");
30129 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
30130 //stripEl.appendChild(td);
30132 td.className = "x-tabs-closable";
30133 if(!this.closeTpl){
30134 this.closeTpl = new Roo.Template(
30135 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
30136 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
30137 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
30140 var el = this.closeTpl.overwrite(td, {"text": text});
30141 var close = el.getElementsByTagName("div")[0];
30142 var inner = el.getElementsByTagName("em")[0];
30143 return {"el": el, "close": close, "inner": inner};
30146 this.tabTpl = new Roo.Template(
30147 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
30148 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
30151 var el = this.tabTpl.overwrite(td, {"text": text});
30152 var inner = el.getElementsByTagName("em")[0];
30153 return {"el": el, "inner": inner};
30157 * Ext JS Library 1.1.1
30158 * Copyright(c) 2006-2007, Ext JS, LLC.
30160 * Originally Released Under LGPL - original licence link has changed is not relivant.
30163 * <script type="text/javascript">
30167 * @class Roo.Button
30168 * @extends Roo.util.Observable
30169 * Simple Button class
30170 * @cfg {String} text The button text
30171 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
30172 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
30173 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
30174 * @cfg {Object} scope The scope of the handler
30175 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
30176 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
30177 * @cfg {Boolean} hidden True to start hidden (defaults to false)
30178 * @cfg {Boolean} disabled True to start disabled (defaults to false)
30179 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
30180 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
30181 applies if enableToggle = true)
30182 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
30183 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
30184 an {@link Roo.util.ClickRepeater} config object (defaults to false).
30186 * Create a new button
30187 * @param {Object} config The config object
30189 Roo.Button = function(renderTo, config)
30193 renderTo = config.renderTo || false;
30196 Roo.apply(this, config);
30200 * Fires when this button is clicked
30201 * @param {Button} this
30202 * @param {EventObject} e The click event
30207 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
30208 * @param {Button} this
30209 * @param {Boolean} pressed
30214 * Fires when the mouse hovers over the button
30215 * @param {Button} this
30216 * @param {Event} e The event object
30218 'mouseover' : true,
30221 * Fires when the mouse exits the button
30222 * @param {Button} this
30223 * @param {Event} e The event object
30228 * Fires when the button is rendered
30229 * @param {Button} this
30234 this.menu = Roo.menu.MenuMgr.get(this.menu);
30236 // register listeners first!! - so render can be captured..
30237 Roo.util.Observable.call(this);
30239 this.render(renderTo);
30245 Roo.extend(Roo.Button, Roo.util.Observable, {
30251 * Read-only. True if this button is hidden
30256 * Read-only. True if this button is disabled
30261 * Read-only. True if this button is pressed (only if enableToggle = true)
30267 * @cfg {Number} tabIndex
30268 * The DOM tabIndex for this button (defaults to undefined)
30270 tabIndex : undefined,
30273 * @cfg {Boolean} enableToggle
30274 * True to enable pressed/not pressed toggling (defaults to false)
30276 enableToggle: false,
30278 * @cfg {Roo.menu.Menu} menu
30279 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
30283 * @cfg {String} menuAlign
30284 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
30286 menuAlign : "tl-bl?",
30289 * @cfg {String} iconCls
30290 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
30292 iconCls : undefined,
30294 * @cfg {String} type
30295 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
30300 menuClassTarget: 'tr',
30303 * @cfg {String} clickEvent
30304 * The type of event to map to the button's event handler (defaults to 'click')
30306 clickEvent : 'click',
30309 * @cfg {Boolean} handleMouseEvents
30310 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
30312 handleMouseEvents : true,
30315 * @cfg {String} tooltipType
30316 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
30318 tooltipType : 'qtip',
30321 * @cfg {String} cls
30322 * A CSS class to apply to the button's main element.
30326 * @cfg {Roo.Template} template (Optional)
30327 * An {@link Roo.Template} with which to create the Button's main element. This Template must
30328 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
30329 * require code modifications if required elements (e.g. a button) aren't present.
30333 render : function(renderTo){
30335 if(this.hideParent){
30336 this.parentEl = Roo.get(renderTo);
30338 if(!this.dhconfig){
30339 if(!this.template){
30340 if(!Roo.Button.buttonTemplate){
30341 // hideous table template
30342 Roo.Button.buttonTemplate = new Roo.Template(
30343 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
30344 '<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>',
30345 "</tr></tbody></table>");
30347 this.template = Roo.Button.buttonTemplate;
30349 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
30350 var btnEl = btn.child("button:first");
30351 btnEl.on('focus', this.onFocus, this);
30352 btnEl.on('blur', this.onBlur, this);
30354 btn.addClass(this.cls);
30357 btnEl.setStyle('background-image', 'url(' +this.icon +')');
30360 btnEl.addClass(this.iconCls);
30362 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
30365 if(this.tabIndex !== undefined){
30366 btnEl.dom.tabIndex = this.tabIndex;
30369 if(typeof this.tooltip == 'object'){
30370 Roo.QuickTips.tips(Roo.apply({
30374 btnEl.dom[this.tooltipType] = this.tooltip;
30378 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
30382 this.el.dom.id = this.el.id = this.id;
30385 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
30386 this.menu.on("show", this.onMenuShow, this);
30387 this.menu.on("hide", this.onMenuHide, this);
30389 btn.addClass("x-btn");
30390 if(Roo.isIE && !Roo.isIE7){
30391 this.autoWidth.defer(1, this);
30395 if(this.handleMouseEvents){
30396 btn.on("mouseover", this.onMouseOver, this);
30397 btn.on("mouseout", this.onMouseOut, this);
30398 btn.on("mousedown", this.onMouseDown, this);
30400 btn.on(this.clickEvent, this.onClick, this);
30401 //btn.on("mouseup", this.onMouseUp, this);
30408 Roo.ButtonToggleMgr.register(this);
30410 this.el.addClass("x-btn-pressed");
30413 var repeater = new Roo.util.ClickRepeater(btn,
30414 typeof this.repeat == "object" ? this.repeat : {}
30416 repeater.on("click", this.onClick, this);
30419 this.fireEvent('render', this);
30423 * Returns the button's underlying element
30424 * @return {Roo.Element} The element
30426 getEl : function(){
30431 * Destroys this Button and removes any listeners.
30433 destroy : function(){
30434 Roo.ButtonToggleMgr.unregister(this);
30435 this.el.removeAllListeners();
30436 this.purgeListeners();
30441 autoWidth : function(){
30443 this.el.setWidth("auto");
30444 if(Roo.isIE7 && Roo.isStrict){
30445 var ib = this.el.child('button');
30446 if(ib && ib.getWidth() > 20){
30448 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30453 this.el.beginMeasure();
30455 if(this.el.getWidth() < this.minWidth){
30456 this.el.setWidth(this.minWidth);
30459 this.el.endMeasure();
30466 * Assigns this button's click handler
30467 * @param {Function} handler The function to call when the button is clicked
30468 * @param {Object} scope (optional) Scope for the function passed in
30470 setHandler : function(handler, scope){
30471 this.handler = handler;
30472 this.scope = scope;
30476 * Sets this button's text
30477 * @param {String} text The button text
30479 setText : function(text){
30482 this.el.child("td.x-btn-center button.x-btn-text").update(text);
30488 * Gets the text for this button
30489 * @return {String} The button text
30491 getText : function(){
30499 this.hidden = false;
30501 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
30509 this.hidden = true;
30511 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
30516 * Convenience function for boolean show/hide
30517 * @param {Boolean} visible True to show, false to hide
30519 setVisible: function(visible){
30528 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
30529 * @param {Boolean} state (optional) Force a particular state
30531 toggle : function(state){
30532 state = state === undefined ? !this.pressed : state;
30533 if(state != this.pressed){
30535 this.el.addClass("x-btn-pressed");
30536 this.pressed = true;
30537 this.fireEvent("toggle", this, true);
30539 this.el.removeClass("x-btn-pressed");
30540 this.pressed = false;
30541 this.fireEvent("toggle", this, false);
30543 if(this.toggleHandler){
30544 this.toggleHandler.call(this.scope || this, this, state);
30552 focus : function(){
30553 this.el.child('button:first').focus();
30557 * Disable this button
30559 disable : function(){
30561 this.el.addClass("x-btn-disabled");
30563 this.disabled = true;
30567 * Enable this button
30569 enable : function(){
30571 this.el.removeClass("x-btn-disabled");
30573 this.disabled = false;
30577 * Convenience function for boolean enable/disable
30578 * @param {Boolean} enabled True to enable, false to disable
30580 setDisabled : function(v){
30581 this[v !== true ? "enable" : "disable"]();
30585 onClick : function(e)
30588 e.preventDefault();
30593 if(!this.disabled){
30594 if(this.enableToggle){
30597 if(this.menu && !this.menu.isVisible()){
30598 this.menu.show(this.el, this.menuAlign);
30600 this.fireEvent("click", this, e);
30602 this.el.removeClass("x-btn-over");
30603 this.handler.call(this.scope || this, this, e);
30608 onMouseOver : function(e){
30609 if(!this.disabled){
30610 this.el.addClass("x-btn-over");
30611 this.fireEvent('mouseover', this, e);
30615 onMouseOut : function(e){
30616 if(!e.within(this.el, true)){
30617 this.el.removeClass("x-btn-over");
30618 this.fireEvent('mouseout', this, e);
30622 onFocus : function(e){
30623 if(!this.disabled){
30624 this.el.addClass("x-btn-focus");
30628 onBlur : function(e){
30629 this.el.removeClass("x-btn-focus");
30632 onMouseDown : function(e){
30633 if(!this.disabled && e.button == 0){
30634 this.el.addClass("x-btn-click");
30635 Roo.get(document).on('mouseup', this.onMouseUp, this);
30639 onMouseUp : function(e){
30641 this.el.removeClass("x-btn-click");
30642 Roo.get(document).un('mouseup', this.onMouseUp, this);
30646 onMenuShow : function(e){
30647 this.el.addClass("x-btn-menu-active");
30650 onMenuHide : function(e){
30651 this.el.removeClass("x-btn-menu-active");
30655 // Private utility class used by Button
30656 Roo.ButtonToggleMgr = function(){
30659 function toggleGroup(btn, state){
30661 var g = groups[btn.toggleGroup];
30662 for(var i = 0, l = g.length; i < l; i++){
30664 g[i].toggle(false);
30671 register : function(btn){
30672 if(!btn.toggleGroup){
30675 var g = groups[btn.toggleGroup];
30677 g = groups[btn.toggleGroup] = [];
30680 btn.on("toggle", toggleGroup);
30683 unregister : function(btn){
30684 if(!btn.toggleGroup){
30687 var g = groups[btn.toggleGroup];
30690 btn.un("toggle", toggleGroup);
30696 * Ext JS Library 1.1.1
30697 * Copyright(c) 2006-2007, Ext JS, LLC.
30699 * Originally Released Under LGPL - original licence link has changed is not relivant.
30702 * <script type="text/javascript">
30706 * @class Roo.SplitButton
30707 * @extends Roo.Button
30708 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
30709 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
30710 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
30711 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
30712 * @cfg {String} arrowTooltip The title attribute of the arrow
30714 * Create a new menu button
30715 * @param {String/HTMLElement/Element} renderTo The element to append the button to
30716 * @param {Object} config The config object
30718 Roo.SplitButton = function(renderTo, config){
30719 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
30721 * @event arrowclick
30722 * Fires when this button's arrow is clicked
30723 * @param {SplitButton} this
30724 * @param {EventObject} e The click event
30726 this.addEvents({"arrowclick":true});
30729 Roo.extend(Roo.SplitButton, Roo.Button, {
30730 render : function(renderTo){
30731 // this is one sweet looking template!
30732 var tpl = new Roo.Template(
30733 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
30734 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
30735 '<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>',
30736 "</tbody></table></td><td>",
30737 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
30738 '<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>',
30739 "</tbody></table></td></tr></table>"
30741 var btn = tpl.append(renderTo, [this.text, this.type], true);
30742 var btnEl = btn.child("button");
30744 btn.addClass(this.cls);
30747 btnEl.setStyle('background-image', 'url(' +this.icon +')');
30750 btnEl.addClass(this.iconCls);
30752 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
30756 if(this.handleMouseEvents){
30757 btn.on("mouseover", this.onMouseOver, this);
30758 btn.on("mouseout", this.onMouseOut, this);
30759 btn.on("mousedown", this.onMouseDown, this);
30760 btn.on("mouseup", this.onMouseUp, this);
30762 btn.on(this.clickEvent, this.onClick, this);
30764 if(typeof this.tooltip == 'object'){
30765 Roo.QuickTips.tips(Roo.apply({
30769 btnEl.dom[this.tooltipType] = this.tooltip;
30772 if(this.arrowTooltip){
30773 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
30782 this.el.addClass("x-btn-pressed");
30784 if(Roo.isIE && !Roo.isIE7){
30785 this.autoWidth.defer(1, this);
30790 this.menu.on("show", this.onMenuShow, this);
30791 this.menu.on("hide", this.onMenuHide, this);
30793 this.fireEvent('render', this);
30797 autoWidth : function(){
30799 var tbl = this.el.child("table:first");
30800 var tbl2 = this.el.child("table:last");
30801 this.el.setWidth("auto");
30802 tbl.setWidth("auto");
30803 if(Roo.isIE7 && Roo.isStrict){
30804 var ib = this.el.child('button:first');
30805 if(ib && ib.getWidth() > 20){
30807 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30812 this.el.beginMeasure();
30814 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
30815 tbl.setWidth(this.minWidth-tbl2.getWidth());
30818 this.el.endMeasure();
30821 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
30825 * Sets this button's click handler
30826 * @param {Function} handler The function to call when the button is clicked
30827 * @param {Object} scope (optional) Scope for the function passed above
30829 setHandler : function(handler, scope){
30830 this.handler = handler;
30831 this.scope = scope;
30835 * Sets this button's arrow click handler
30836 * @param {Function} handler The function to call when the arrow is clicked
30837 * @param {Object} scope (optional) Scope for the function passed above
30839 setArrowHandler : function(handler, scope){
30840 this.arrowHandler = handler;
30841 this.scope = scope;
30847 focus : function(){
30849 this.el.child("button:first").focus();
30854 onClick : function(e){
30855 e.preventDefault();
30856 if(!this.disabled){
30857 if(e.getTarget(".x-btn-menu-arrow-wrap")){
30858 if(this.menu && !this.menu.isVisible()){
30859 this.menu.show(this.el, this.menuAlign);
30861 this.fireEvent("arrowclick", this, e);
30862 if(this.arrowHandler){
30863 this.arrowHandler.call(this.scope || this, this, e);
30866 this.fireEvent("click", this, e);
30868 this.handler.call(this.scope || this, this, e);
30874 onMouseDown : function(e){
30875 if(!this.disabled){
30876 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30880 onMouseUp : function(e){
30881 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30886 // backwards compat
30887 Roo.MenuButton = Roo.SplitButton;/*
30889 * Ext JS Library 1.1.1
30890 * Copyright(c) 2006-2007, Ext JS, LLC.
30892 * Originally Released Under LGPL - original licence link has changed is not relivant.
30895 * <script type="text/javascript">
30899 * @class Roo.Toolbar
30900 * @children Roo.Toolbar.Item Roo.form.Field
30901 * Basic Toolbar class.
30903 * Creates a new Toolbar
30904 * @param {Object} container The config object
30906 Roo.Toolbar = function(container, buttons, config)
30908 /// old consturctor format still supported..
30909 if(container instanceof Array){ // omit the container for later rendering
30910 buttons = container;
30914 if (typeof(container) == 'object' && container.xtype) {
30915 config = container;
30916 container = config.container;
30917 buttons = config.buttons || []; // not really - use items!!
30920 if (config && config.items) {
30921 xitems = config.items;
30922 delete config.items;
30924 Roo.apply(this, config);
30925 this.buttons = buttons;
30928 this.render(container);
30930 this.xitems = xitems;
30931 Roo.each(xitems, function(b) {
30937 Roo.Toolbar.prototype = {
30939 * @cfg {Array} items
30940 * array of button configs or elements to add (will be converted to a MixedCollection)
30944 * @cfg {String/HTMLElement/Element} container
30945 * The id or element that will contain the toolbar
30948 render : function(ct){
30949 this.el = Roo.get(ct);
30951 this.el.addClass(this.cls);
30953 // using a table allows for vertical alignment
30954 // 100% width is needed by Safari...
30955 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30956 this.tr = this.el.child("tr", true);
30958 this.items = new Roo.util.MixedCollection(false, function(o){
30959 return o.id || ("item" + (++autoId));
30962 this.add.apply(this, this.buttons);
30963 delete this.buttons;
30968 * Adds element(s) to the toolbar -- this function takes a variable number of
30969 * arguments of mixed type and adds them to the toolbar.
30970 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30972 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30973 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30974 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30975 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30976 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30977 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30978 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30979 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30980 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30982 * @param {Mixed} arg2
30983 * @param {Mixed} etc.
30986 var a = arguments, l = a.length;
30987 for(var i = 0; i < l; i++){
30992 _add : function(el) {
30995 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30998 if (el.applyTo){ // some kind of form field
30999 return this.addField(el);
31001 if (el.render){ // some kind of Toolbar.Item
31002 return this.addItem(el);
31004 if (typeof el == "string"){ // string
31005 if(el == "separator" || el == "-"){
31006 return this.addSeparator();
31009 return this.addSpacer();
31012 return this.addFill();
31014 return this.addText(el);
31017 if(el.tagName){ // element
31018 return this.addElement(el);
31020 if(typeof el == "object"){ // must be button config?
31021 return this.addButton(el);
31023 // and now what?!?!
31029 * Add an Xtype element
31030 * @param {Object} xtype Xtype Object
31031 * @return {Object} created Object
31033 addxtype : function(e){
31034 return this.add(e);
31038 * Returns the Element for this toolbar.
31039 * @return {Roo.Element}
31041 getEl : function(){
31047 * @return {Roo.Toolbar.Item} The separator item
31049 addSeparator : function(){
31050 return this.addItem(new Roo.Toolbar.Separator());
31054 * Adds a spacer element
31055 * @return {Roo.Toolbar.Spacer} The spacer item
31057 addSpacer : function(){
31058 return this.addItem(new Roo.Toolbar.Spacer());
31062 * Adds a fill element that forces subsequent additions to the right side of the toolbar
31063 * @return {Roo.Toolbar.Fill} The fill item
31065 addFill : function(){
31066 return this.addItem(new Roo.Toolbar.Fill());
31070 * Adds any standard HTML element to the toolbar
31071 * @param {String/HTMLElement/Element} el The element or id of the element to add
31072 * @return {Roo.Toolbar.Item} The element's item
31074 addElement : function(el){
31075 return this.addItem(new Roo.Toolbar.Item(el));
31078 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
31079 * @type Roo.util.MixedCollection
31084 * Adds any Toolbar.Item or subclass
31085 * @param {Roo.Toolbar.Item} item
31086 * @return {Roo.Toolbar.Item} The item
31088 addItem : function(item){
31089 var td = this.nextBlock();
31091 this.items.add(item);
31096 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
31097 * @param {Object/Array} config A button config or array of configs
31098 * @return {Roo.Toolbar.Button/Array}
31100 addButton : function(config){
31101 if(config instanceof Array){
31103 for(var i = 0, len = config.length; i < len; i++) {
31104 buttons.push(this.addButton(config[i]));
31109 if(!(config instanceof Roo.Toolbar.Button)){
31111 new Roo.Toolbar.SplitButton(config) :
31112 new Roo.Toolbar.Button(config);
31114 var td = this.nextBlock();
31121 * Adds text to the toolbar
31122 * @param {String} text The text to add
31123 * @return {Roo.Toolbar.Item} The element's item
31125 addText : function(text){
31126 return this.addItem(new Roo.Toolbar.TextItem(text));
31130 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
31131 * @param {Number} index The index where the item is to be inserted
31132 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
31133 * @return {Roo.Toolbar.Button/Item}
31135 insertButton : function(index, item){
31136 if(item instanceof Array){
31138 for(var i = 0, len = item.length; i < len; i++) {
31139 buttons.push(this.insertButton(index + i, item[i]));
31143 if (!(item instanceof Roo.Toolbar.Button)){
31144 item = new Roo.Toolbar.Button(item);
31146 var td = document.createElement("td");
31147 this.tr.insertBefore(td, this.tr.childNodes[index]);
31149 this.items.insert(index, item);
31154 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
31155 * @param {Object} config
31156 * @return {Roo.Toolbar.Item} The element's item
31158 addDom : function(config, returnEl){
31159 var td = this.nextBlock();
31160 Roo.DomHelper.overwrite(td, config);
31161 var ti = new Roo.Toolbar.Item(td.firstChild);
31163 this.items.add(ti);
31168 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
31169 * @type Roo.util.MixedCollection
31174 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
31175 * Note: the field should not have been rendered yet. For a field that has already been
31176 * rendered, use {@link #addElement}.
31177 * @param {Roo.form.Field} field
31178 * @return {Roo.ToolbarItem}
31182 addField : function(field) {
31183 if (!this.fields) {
31185 this.fields = new Roo.util.MixedCollection(false, function(o){
31186 return o.id || ("item" + (++autoId));
31191 var td = this.nextBlock();
31193 var ti = new Roo.Toolbar.Item(td.firstChild);
31195 this.items.add(ti);
31196 this.fields.add(field);
31207 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
31208 this.el.child('div').hide();
31216 this.el.child('div').show();
31220 nextBlock : function(){
31221 var td = document.createElement("td");
31222 this.tr.appendChild(td);
31227 destroy : function(){
31228 if(this.items){ // rendered?
31229 Roo.destroy.apply(Roo, this.items.items);
31231 if(this.fields){ // rendered?
31232 Roo.destroy.apply(Roo, this.fields.items);
31234 Roo.Element.uncache(this.el, this.tr);
31239 * @class Roo.Toolbar.Item
31240 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
31242 * Creates a new Item
31243 * @param {HTMLElement} el
31245 Roo.Toolbar.Item = function(el){
31247 if (typeof (el.xtype) != 'undefined') {
31252 this.el = Roo.getDom(el);
31253 this.id = Roo.id(this.el);
31254 this.hidden = false;
31259 * Fires when the button is rendered
31260 * @param {Button} this
31264 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
31266 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
31267 //Roo.Toolbar.Item.prototype = {
31270 * Get this item's HTML Element
31271 * @return {HTMLElement}
31273 getEl : function(){
31278 render : function(td){
31281 td.appendChild(this.el);
31283 this.fireEvent('render', this);
31287 * Removes and destroys this item.
31289 destroy : function(){
31290 this.td.parentNode.removeChild(this.td);
31297 this.hidden = false;
31298 this.td.style.display = "";
31305 this.hidden = true;
31306 this.td.style.display = "none";
31310 * Convenience function for boolean show/hide.
31311 * @param {Boolean} visible true to show/false to hide
31313 setVisible: function(visible){
31322 * Try to focus this item.
31324 focus : function(){
31325 Roo.fly(this.el).focus();
31329 * Disables this item.
31331 disable : function(){
31332 Roo.fly(this.td).addClass("x-item-disabled");
31333 this.disabled = true;
31334 this.el.disabled = true;
31338 * Enables this item.
31340 enable : function(){
31341 Roo.fly(this.td).removeClass("x-item-disabled");
31342 this.disabled = false;
31343 this.el.disabled = false;
31349 * @class Roo.Toolbar.Separator
31350 * @extends Roo.Toolbar.Item
31351 * A simple toolbar separator class
31353 * Creates a new Separator
31355 Roo.Toolbar.Separator = function(cfg){
31357 var s = document.createElement("span");
31358 s.className = "ytb-sep";
31363 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
31365 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
31366 enable:Roo.emptyFn,
31367 disable:Roo.emptyFn,
31372 * @class Roo.Toolbar.Spacer
31373 * @extends Roo.Toolbar.Item
31374 * A simple element that adds extra horizontal space to a toolbar.
31376 * Creates a new Spacer
31378 Roo.Toolbar.Spacer = function(cfg){
31379 var s = document.createElement("div");
31380 s.className = "ytb-spacer";
31384 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
31386 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
31387 enable:Roo.emptyFn,
31388 disable:Roo.emptyFn,
31393 * @class Roo.Toolbar.Fill
31394 * @extends Roo.Toolbar.Spacer
31395 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
31397 * Creates a new Spacer
31399 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
31401 render : function(td){
31402 td.style.width = '100%';
31403 Roo.Toolbar.Fill.superclass.render.call(this, td);
31408 * @class Roo.Toolbar.TextItem
31409 * @extends Roo.Toolbar.Item
31410 * A simple class that renders text directly into a toolbar.
31412 * Creates a new TextItem
31413 * @cfg {string} text
31415 Roo.Toolbar.TextItem = function(cfg){
31416 var text = cfg || "";
31417 if (typeof(cfg) == 'object') {
31418 text = cfg.text || "";
31422 var s = document.createElement("span");
31423 s.className = "ytb-text";
31424 s.innerHTML = text;
31429 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
31431 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
31434 enable:Roo.emptyFn,
31435 disable:Roo.emptyFn,
31440 * @class Roo.Toolbar.Button
31441 * @extends Roo.Button
31442 * A button that renders into a toolbar.
31444 * Creates a new Button
31445 * @param {Object} config A standard {@link Roo.Button} config object
31447 Roo.Toolbar.Button = function(config){
31448 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
31450 Roo.extend(Roo.Toolbar.Button, Roo.Button,
31454 render : function(td){
31456 Roo.Toolbar.Button.superclass.render.call(this, td);
31460 * Removes and destroys this button
31462 destroy : function(){
31463 Roo.Toolbar.Button.superclass.destroy.call(this);
31464 this.td.parentNode.removeChild(this.td);
31468 * Shows this button
31471 this.hidden = false;
31472 this.td.style.display = "";
31476 * Hides this button
31479 this.hidden = true;
31480 this.td.style.display = "none";
31484 * Disables this item
31486 disable : function(){
31487 Roo.fly(this.td).addClass("x-item-disabled");
31488 this.disabled = true;
31492 * Enables this item
31494 enable : function(){
31495 Roo.fly(this.td).removeClass("x-item-disabled");
31496 this.disabled = false;
31499 // backwards compat
31500 Roo.ToolbarButton = Roo.Toolbar.Button;
31503 * @class Roo.Toolbar.SplitButton
31504 * @extends Roo.SplitButton
31505 * A menu button that renders into a toolbar.
31507 * Creates a new SplitButton
31508 * @param {Object} config A standard {@link Roo.SplitButton} config object
31510 Roo.Toolbar.SplitButton = function(config){
31511 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
31513 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
31514 render : function(td){
31516 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
31520 * Removes and destroys this button
31522 destroy : function(){
31523 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
31524 this.td.parentNode.removeChild(this.td);
31528 * Shows this button
31531 this.hidden = false;
31532 this.td.style.display = "";
31536 * Hides this button
31539 this.hidden = true;
31540 this.td.style.display = "none";
31544 // backwards compat
31545 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
31547 * Ext JS Library 1.1.1
31548 * Copyright(c) 2006-2007, Ext JS, LLC.
31550 * Originally Released Under LGPL - original licence link has changed is not relivant.
31553 * <script type="text/javascript">
31557 * @class Roo.PagingToolbar
31558 * @extends Roo.Toolbar
31559 * @children Roo.Toolbar.Item Roo.form.Field
31560 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
31562 * Create a new PagingToolbar
31563 * @param {Object} config The config object
31565 Roo.PagingToolbar = function(el, ds, config)
31567 // old args format still supported... - xtype is prefered..
31568 if (typeof(el) == 'object' && el.xtype) {
31569 // created from xtype...
31571 ds = el.dataSource;
31572 el = config.container;
31575 if (config.items) {
31576 items = config.items;
31580 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
31583 this.renderButtons(this.el);
31586 // supprot items array.
31588 Roo.each(items, function(e) {
31589 this.add(Roo.factory(e));
31594 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
31597 * @cfg {String/HTMLElement/Element} container
31598 * container The id or element that will contain the toolbar
31601 * @cfg {Boolean} displayInfo
31602 * True to display the displayMsg (defaults to false)
31607 * @cfg {Number} pageSize
31608 * The number of records to display per page (defaults to 20)
31612 * @cfg {String} displayMsg
31613 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
31615 displayMsg : 'Displaying {0} - {1} of {2}',
31617 * @cfg {String} emptyMsg
31618 * The message to display when no records are found (defaults to "No data to display")
31620 emptyMsg : 'No data to display',
31622 * Customizable piece of the default paging text (defaults to "Page")
31625 beforePageText : "Page",
31627 * Customizable piece of the default paging text (defaults to "of %0")
31630 afterPageText : "of {0}",
31632 * Customizable piece of the default paging text (defaults to "First Page")
31635 firstText : "First Page",
31637 * Customizable piece of the default paging text (defaults to "Previous Page")
31640 prevText : "Previous Page",
31642 * Customizable piece of the default paging text (defaults to "Next Page")
31645 nextText : "Next Page",
31647 * Customizable piece of the default paging text (defaults to "Last Page")
31650 lastText : "Last Page",
31652 * Customizable piece of the default paging text (defaults to "Refresh")
31655 refreshText : "Refresh",
31658 renderButtons : function(el){
31659 Roo.PagingToolbar.superclass.render.call(this, el);
31660 this.first = this.addButton({
31661 tooltip: this.firstText,
31662 cls: "x-btn-icon x-grid-page-first",
31664 handler: this.onClick.createDelegate(this, ["first"])
31666 this.prev = this.addButton({
31667 tooltip: this.prevText,
31668 cls: "x-btn-icon x-grid-page-prev",
31670 handler: this.onClick.createDelegate(this, ["prev"])
31672 //this.addSeparator();
31673 this.add(this.beforePageText);
31674 this.field = Roo.get(this.addDom({
31679 cls: "x-grid-page-number"
31681 this.field.on("keydown", this.onPagingKeydown, this);
31682 this.field.on("focus", function(){this.dom.select();});
31683 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
31684 this.field.setHeight(18);
31685 //this.addSeparator();
31686 this.next = this.addButton({
31687 tooltip: this.nextText,
31688 cls: "x-btn-icon x-grid-page-next",
31690 handler: this.onClick.createDelegate(this, ["next"])
31692 this.last = this.addButton({
31693 tooltip: this.lastText,
31694 cls: "x-btn-icon x-grid-page-last",
31696 handler: this.onClick.createDelegate(this, ["last"])
31698 //this.addSeparator();
31699 this.loading = this.addButton({
31700 tooltip: this.refreshText,
31701 cls: "x-btn-icon x-grid-loading",
31702 handler: this.onClick.createDelegate(this, ["refresh"])
31705 if(this.displayInfo){
31706 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
31711 updateInfo : function(){
31712 if(this.displayEl){
31713 var count = this.ds.getCount();
31714 var msg = count == 0 ?
31718 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
31720 this.displayEl.update(msg);
31725 onLoad : function(ds, r, o){
31726 this.cursor = o.params ? o.params.start : 0;
31727 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
31729 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
31730 this.field.dom.value = ap;
31731 this.first.setDisabled(ap == 1);
31732 this.prev.setDisabled(ap == 1);
31733 this.next.setDisabled(ap == ps);
31734 this.last.setDisabled(ap == ps);
31735 this.loading.enable();
31740 getPageData : function(){
31741 var total = this.ds.getTotalCount();
31744 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
31745 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
31750 onLoadError : function(){
31751 this.loading.enable();
31755 onPagingKeydown : function(e){
31756 var k = e.getKey();
31757 var d = this.getPageData();
31759 var v = this.field.dom.value, pageNum;
31760 if(!v || isNaN(pageNum = parseInt(v, 10))){
31761 this.field.dom.value = d.activePage;
31764 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
31765 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31768 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))
31770 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
31771 this.field.dom.value = pageNum;
31772 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
31775 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
31777 var v = this.field.dom.value, pageNum;
31778 var increment = (e.shiftKey) ? 10 : 1;
31779 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
31782 if(!v || isNaN(pageNum = parseInt(v, 10))) {
31783 this.field.dom.value = d.activePage;
31786 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
31788 this.field.dom.value = parseInt(v, 10) + increment;
31789 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
31790 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31797 beforeLoad : function(){
31799 this.loading.disable();
31804 onClick : function(which){
31808 ds.load({params:{start: 0, limit: this.pageSize}});
31811 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
31814 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
31817 var total = ds.getTotalCount();
31818 var extra = total % this.pageSize;
31819 var lastStart = extra ? (total - extra) : total-this.pageSize;
31820 ds.load({params:{start: lastStart, limit: this.pageSize}});
31823 ds.load({params:{start: this.cursor, limit: this.pageSize}});
31829 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
31830 * @param {Roo.data.Store} store The data store to unbind
31832 unbind : function(ds){
31833 ds.un("beforeload", this.beforeLoad, this);
31834 ds.un("load", this.onLoad, this);
31835 ds.un("loadexception", this.onLoadError, this);
31836 ds.un("remove", this.updateInfo, this);
31837 ds.un("add", this.updateInfo, this);
31838 this.ds = undefined;
31842 * Binds the paging toolbar to the specified {@link Roo.data.Store}
31843 * @param {Roo.data.Store} store The data store to bind
31845 bind : function(ds){
31846 ds.on("beforeload", this.beforeLoad, this);
31847 ds.on("load", this.onLoad, this);
31848 ds.on("loadexception", this.onLoadError, this);
31849 ds.on("remove", this.updateInfo, this);
31850 ds.on("add", this.updateInfo, this);
31855 * Ext JS Library 1.1.1
31856 * Copyright(c) 2006-2007, Ext JS, LLC.
31858 * Originally Released Under LGPL - original licence link has changed is not relivant.
31861 * <script type="text/javascript">
31865 * @class Roo.Resizable
31866 * @extends Roo.util.Observable
31867 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
31868 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
31869 * 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
31870 * the element will be wrapped for you automatically.</p>
31871 * <p>Here is the list of valid resize handles:</p>
31874 ------ -------------------
31883 'hd' horizontal drag
31886 * <p>Here's an example showing the creation of a typical Resizable:</p>
31888 var resizer = new Roo.Resizable("element-id", {
31896 resizer.on("resize", myHandler);
31898 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31899 * resizer.east.setDisplayed(false);</p>
31900 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31901 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31902 * resize operation's new size (defaults to [0, 0])
31903 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31904 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31905 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31906 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31907 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31908 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31909 * @cfg {Number} width The width of the element in pixels (defaults to null)
31910 * @cfg {Number} height The height of the element in pixels (defaults to null)
31911 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31912 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31913 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31914 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31915 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31916 * in favor of the handles config option (defaults to false)
31917 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31918 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31919 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31920 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31921 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31922 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31923 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31924 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31925 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31926 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31927 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31929 * Create a new resizable component
31930 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31931 * @param {Object} config configuration options
31933 Roo.Resizable = function(el, config)
31935 this.el = Roo.get(el);
31937 if(config && config.wrap){
31938 config.resizeChild = this.el;
31939 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31940 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31941 this.el.setStyle("overflow", "hidden");
31942 this.el.setPositioning(config.resizeChild.getPositioning());
31943 config.resizeChild.clearPositioning();
31944 if(!config.width || !config.height){
31945 var csize = config.resizeChild.getSize();
31946 this.el.setSize(csize.width, csize.height);
31948 if(config.pinned && !config.adjustments){
31949 config.adjustments = "auto";
31953 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31954 this.proxy.unselectable();
31955 this.proxy.enableDisplayMode('block');
31957 Roo.apply(this, config);
31960 this.disableTrackOver = true;
31961 this.el.addClass("x-resizable-pinned");
31963 // if the element isn't positioned, make it relative
31964 var position = this.el.getStyle("position");
31965 if(position != "absolute" && position != "fixed"){
31966 this.el.setStyle("position", "relative");
31968 if(!this.handles){ // no handles passed, must be legacy style
31969 this.handles = 's,e,se';
31970 if(this.multiDirectional){
31971 this.handles += ',n,w';
31974 if(this.handles == "all"){
31975 this.handles = "n s e w ne nw se sw";
31977 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31978 var ps = Roo.Resizable.positions;
31979 for(var i = 0, len = hs.length; i < len; i++){
31980 if(hs[i] && ps[hs[i]]){
31981 var pos = ps[hs[i]];
31982 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31986 this.corner = this.southeast;
31988 // updateBox = the box can move..
31989 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31990 this.updateBox = true;
31993 this.activeHandle = null;
31995 if(this.resizeChild){
31996 if(typeof this.resizeChild == "boolean"){
31997 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31999 this.resizeChild = Roo.get(this.resizeChild, true);
32003 if(this.adjustments == "auto"){
32004 var rc = this.resizeChild;
32005 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
32006 if(rc && (hw || hn)){
32007 rc.position("relative");
32008 rc.setLeft(hw ? hw.el.getWidth() : 0);
32009 rc.setTop(hn ? hn.el.getHeight() : 0);
32011 this.adjustments = [
32012 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
32013 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
32017 if(this.draggable){
32018 this.dd = this.dynamic ?
32019 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
32020 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
32026 * @event beforeresize
32027 * Fired before resize is allowed. Set enabled to false to cancel resize.
32028 * @param {Roo.Resizable} this
32029 * @param {Roo.EventObject} e The mousedown event
32031 "beforeresize" : true,
32034 * Fired a resizing.
32035 * @param {Roo.Resizable} this
32036 * @param {Number} x The new x position
32037 * @param {Number} y The new y position
32038 * @param {Number} w The new w width
32039 * @param {Number} h The new h hight
32040 * @param {Roo.EventObject} e The mouseup event
32045 * Fired after a resize.
32046 * @param {Roo.Resizable} this
32047 * @param {Number} width The new width
32048 * @param {Number} height The new height
32049 * @param {Roo.EventObject} e The mouseup event
32054 if(this.width !== null && this.height !== null){
32055 this.resizeTo(this.width, this.height);
32057 this.updateChildSize();
32060 this.el.dom.style.zoom = 1;
32062 Roo.Resizable.superclass.constructor.call(this);
32065 Roo.extend(Roo.Resizable, Roo.util.Observable, {
32066 resizeChild : false,
32067 adjustments : [0, 0],
32077 multiDirectional : false,
32078 disableTrackOver : false,
32079 easing : 'easeOutStrong',
32080 widthIncrement : 0,
32081 heightIncrement : 0,
32085 preserveRatio : false,
32086 transparent: false,
32092 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
32094 constrainTo: undefined,
32096 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
32098 resizeRegion: undefined,
32102 * Perform a manual resize
32103 * @param {Number} width
32104 * @param {Number} height
32106 resizeTo : function(width, height){
32107 this.el.setSize(width, height);
32108 this.updateChildSize();
32109 this.fireEvent("resize", this, width, height, null);
32113 startSizing : function(e, handle){
32114 this.fireEvent("beforeresize", this, e);
32115 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
32118 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
32119 this.overlay.unselectable();
32120 this.overlay.enableDisplayMode("block");
32121 this.overlay.on("mousemove", this.onMouseMove, this);
32122 this.overlay.on("mouseup", this.onMouseUp, this);
32124 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
32126 this.resizing = true;
32127 this.startBox = this.el.getBox();
32128 this.startPoint = e.getXY();
32129 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
32130 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
32132 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32133 this.overlay.show();
32135 if(this.constrainTo) {
32136 var ct = Roo.get(this.constrainTo);
32137 this.resizeRegion = ct.getRegion().adjust(
32138 ct.getFrameWidth('t'),
32139 ct.getFrameWidth('l'),
32140 -ct.getFrameWidth('b'),
32141 -ct.getFrameWidth('r')
32145 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
32147 this.proxy.setBox(this.startBox);
32149 this.proxy.setStyle('visibility', 'visible');
32155 onMouseDown : function(handle, e){
32158 this.activeHandle = handle;
32159 this.startSizing(e, handle);
32164 onMouseUp : function(e){
32165 var size = this.resizeElement();
32166 this.resizing = false;
32168 this.overlay.hide();
32170 this.fireEvent("resize", this, size.width, size.height, e);
32174 updateChildSize : function(){
32176 if(this.resizeChild){
32178 var child = this.resizeChild;
32179 var adj = this.adjustments;
32180 if(el.dom.offsetWidth){
32181 var b = el.getSize(true);
32182 child.setSize(b.width+adj[0], b.height+adj[1]);
32184 // Second call here for IE
32185 // The first call enables instant resizing and
32186 // the second call corrects scroll bars if they
32189 setTimeout(function(){
32190 if(el.dom.offsetWidth){
32191 var b = el.getSize(true);
32192 child.setSize(b.width+adj[0], b.height+adj[1]);
32200 snap : function(value, inc, min){
32201 if(!inc || !value) {
32204 var newValue = value;
32205 var m = value % inc;
32208 newValue = value + (inc-m);
32210 newValue = value - m;
32213 return Math.max(min, newValue);
32217 resizeElement : function(){
32218 var box = this.proxy.getBox();
32219 if(this.updateBox){
32220 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
32222 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
32224 this.updateChildSize();
32232 constrain : function(v, diff, m, mx){
32235 }else if(v - diff > mx){
32242 onMouseMove : function(e){
32245 try{// try catch so if something goes wrong the user doesn't get hung
32247 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
32251 //var curXY = this.startPoint;
32252 var curSize = this.curSize || this.startBox;
32253 var x = this.startBox.x, y = this.startBox.y;
32254 var ox = x, oy = y;
32255 var w = curSize.width, h = curSize.height;
32256 var ow = w, oh = h;
32257 var mw = this.minWidth, mh = this.minHeight;
32258 var mxw = this.maxWidth, mxh = this.maxHeight;
32259 var wi = this.widthIncrement;
32260 var hi = this.heightIncrement;
32262 var eventXY = e.getXY();
32263 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
32264 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
32266 var pos = this.activeHandle.position;
32271 w = Math.min(Math.max(mw, w), mxw);
32276 h = Math.min(Math.max(mh, h), mxh);
32281 w = Math.min(Math.max(mw, w), mxw);
32282 h = Math.min(Math.max(mh, h), mxh);
32285 diffY = this.constrain(h, diffY, mh, mxh);
32292 var adiffX = Math.abs(diffX);
32293 var sub = (adiffX % wi); // how much
32294 if (sub > (wi/2)) { // far enough to snap
32295 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
32297 // remove difference..
32298 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
32302 x = Math.max(this.minX, x);
32305 diffX = this.constrain(w, diffX, mw, mxw);
32311 w = Math.min(Math.max(mw, w), mxw);
32312 diffY = this.constrain(h, diffY, mh, mxh);
32317 diffX = this.constrain(w, diffX, mw, mxw);
32318 diffY = this.constrain(h, diffY, mh, mxh);
32325 diffX = this.constrain(w, diffX, mw, mxw);
32327 h = Math.min(Math.max(mh, h), mxh);
32333 var sw = this.snap(w, wi, mw);
32334 var sh = this.snap(h, hi, mh);
32335 if(sw != w || sh != h){
32358 if(this.preserveRatio){
32363 h = Math.min(Math.max(mh, h), mxh);
32368 w = Math.min(Math.max(mw, w), mxw);
32373 w = Math.min(Math.max(mw, w), mxw);
32379 w = Math.min(Math.max(mw, w), mxw);
32385 h = Math.min(Math.max(mh, h), mxh);
32393 h = Math.min(Math.max(mh, h), mxh);
32403 h = Math.min(Math.max(mh, h), mxh);
32411 if (pos == 'hdrag') {
32414 this.proxy.setBounds(x, y, w, h);
32416 this.resizeElement();
32420 this.fireEvent("resizing", this, x, y, w, h, e);
32424 handleOver : function(){
32426 this.el.addClass("x-resizable-over");
32431 handleOut : function(){
32432 if(!this.resizing){
32433 this.el.removeClass("x-resizable-over");
32438 * Returns the element this component is bound to.
32439 * @return {Roo.Element}
32441 getEl : function(){
32446 * Returns the resizeChild element (or null).
32447 * @return {Roo.Element}
32449 getResizeChild : function(){
32450 return this.resizeChild;
32452 groupHandler : function()
32457 * Destroys this resizable. If the element was wrapped and
32458 * removeEl is not true then the element remains.
32459 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32461 destroy : function(removeEl){
32462 this.proxy.remove();
32464 this.overlay.removeAllListeners();
32465 this.overlay.remove();
32467 var ps = Roo.Resizable.positions;
32469 if(typeof ps[k] != "function" && this[ps[k]]){
32470 var h = this[ps[k]];
32471 h.el.removeAllListeners();
32476 this.el.update("");
32483 // hash to map config positions to true positions
32484 Roo.Resizable.positions = {
32485 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
32490 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
32492 // only initialize the template if resizable is used
32493 var tpl = Roo.DomHelper.createTemplate(
32494 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
32497 Roo.Resizable.Handle.prototype.tpl = tpl;
32499 this.position = pos;
32501 // show north drag fro topdra
32502 var handlepos = pos == 'hdrag' ? 'north' : pos;
32504 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
32505 if (pos == 'hdrag') {
32506 this.el.setStyle('cursor', 'pointer');
32508 this.el.unselectable();
32510 this.el.setOpacity(0);
32512 this.el.on("mousedown", this.onMouseDown, this);
32513 if(!disableTrackOver){
32514 this.el.on("mouseover", this.onMouseOver, this);
32515 this.el.on("mouseout", this.onMouseOut, this);
32520 Roo.Resizable.Handle.prototype = {
32521 afterResize : function(rz){
32526 onMouseDown : function(e){
32527 this.rz.onMouseDown(this, e);
32530 onMouseOver : function(e){
32531 this.rz.handleOver(this, e);
32534 onMouseOut : function(e){
32535 this.rz.handleOut(this, e);
32539 * Ext JS Library 1.1.1
32540 * Copyright(c) 2006-2007, Ext JS, LLC.
32542 * Originally Released Under LGPL - original licence link has changed is not relivant.
32545 * <script type="text/javascript">
32549 * @class Roo.Editor
32550 * @extends Roo.Component
32551 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
32553 * Create a new Editor
32554 * @param {Roo.form.Field} field The Field object (or descendant)
32555 * @param {Object} config The config object
32557 Roo.Editor = function(field, config){
32558 Roo.Editor.superclass.constructor.call(this, config);
32559 this.field = field;
32562 * @event beforestartedit
32563 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
32564 * false from the handler of this event.
32565 * @param {Editor} this
32566 * @param {Roo.Element} boundEl The underlying element bound to this editor
32567 * @param {Mixed} value The field value being set
32569 "beforestartedit" : true,
32572 * Fires when this editor is displayed
32573 * @param {Roo.Element} boundEl The underlying element bound to this editor
32574 * @param {Mixed} value The starting field value
32576 "startedit" : true,
32578 * @event beforecomplete
32579 * Fires after a change has been made to the field, but before the change is reflected in the underlying
32580 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
32581 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
32582 * event will not fire since no edit actually occurred.
32583 * @param {Editor} this
32584 * @param {Mixed} value The current field value
32585 * @param {Mixed} startValue The original field value
32587 "beforecomplete" : true,
32590 * Fires after editing is complete and any changed value has been written to the underlying field.
32591 * @param {Editor} this
32592 * @param {Mixed} value The current field value
32593 * @param {Mixed} startValue The original field value
32597 * @event specialkey
32598 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
32599 * {@link Roo.EventObject#getKey} to determine which key was pressed.
32600 * @param {Roo.form.Field} this
32601 * @param {Roo.EventObject} e The event object
32603 "specialkey" : true
32607 Roo.extend(Roo.Editor, Roo.Component, {
32609 * @cfg {Boolean/String} autosize
32610 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
32611 * or "height" to adopt the height only (defaults to false)
32614 * @cfg {Boolean} revertInvalid
32615 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
32616 * validation fails (defaults to true)
32619 * @cfg {Boolean} ignoreNoChange
32620 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
32621 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
32622 * will never be ignored.
32625 * @cfg {Boolean} hideEl
32626 * False to keep the bound element visible while the editor is displayed (defaults to true)
32629 * @cfg {Mixed} value
32630 * The data value of the underlying field (defaults to "")
32634 * @cfg {String} alignment
32635 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
32639 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
32640 * for bottom-right shadow (defaults to "frame")
32644 * @cfg {Boolean} constrain True to constrain the editor to the viewport
32648 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
32650 completeOnEnter : false,
32652 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
32654 cancelOnEsc : false,
32656 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
32661 onRender : function(ct, position){
32662 this.el = new Roo.Layer({
32663 shadow: this.shadow,
32669 constrain: this.constrain
32671 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
32672 if(this.field.msgTarget != 'title'){
32673 this.field.msgTarget = 'qtip';
32675 this.field.render(this.el);
32677 this.field.el.dom.setAttribute('autocomplete', 'off');
32679 this.field.on("specialkey", this.onSpecialKey, this);
32680 if(this.swallowKeys){
32681 this.field.el.swallowEvent(['keydown','keypress']);
32684 this.field.on("blur", this.onBlur, this);
32685 if(this.field.grow){
32686 this.field.on("autosize", this.el.sync, this.el, {delay:1});
32690 onSpecialKey : function(field, e)
32692 //Roo.log('editor onSpecialKey');
32693 if(this.completeOnEnter && e.getKey() == e.ENTER){
32695 this.completeEdit();
32698 // do not fire special key otherwise it might hide close the editor...
32699 if(e.getKey() == e.ENTER){
32702 if(this.cancelOnEsc && e.getKey() == e.ESC){
32706 this.fireEvent('specialkey', field, e);
32711 * Starts the editing process and shows the editor.
32712 * @param {String/HTMLElement/Element} el The element to edit
32713 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
32714 * to the innerHTML of el.
32716 startEdit : function(el, value){
32718 this.completeEdit();
32720 this.boundEl = Roo.get(el);
32721 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
32722 if(!this.rendered){
32723 this.render(this.parentEl || document.body);
32725 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
32728 this.startValue = v;
32729 this.field.setValue(v);
32731 var sz = this.boundEl.getSize();
32732 switch(this.autoSize){
32734 this.setSize(sz.width, "");
32737 this.setSize("", sz.height);
32740 this.setSize(sz.width, sz.height);
32743 this.el.alignTo(this.boundEl, this.alignment);
32744 this.editing = true;
32746 Roo.QuickTips.disable();
32752 * Sets the height and width of this editor.
32753 * @param {Number} width The new width
32754 * @param {Number} height The new height
32756 setSize : function(w, h){
32757 this.field.setSize(w, h);
32764 * Realigns the editor to the bound field based on the current alignment config value.
32766 realign : function(){
32767 this.el.alignTo(this.boundEl, this.alignment);
32771 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
32772 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
32774 completeEdit : function(remainVisible){
32778 var v = this.getValue();
32779 if(this.revertInvalid !== false && !this.field.isValid()){
32780 v = this.startValue;
32781 this.cancelEdit(true);
32783 if(String(v) === String(this.startValue) && this.ignoreNoChange){
32784 this.editing = false;
32788 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
32789 this.editing = false;
32790 if(this.updateEl && this.boundEl){
32791 this.boundEl.update(v);
32793 if(remainVisible !== true){
32796 this.fireEvent("complete", this, v, this.startValue);
32801 onShow : function(){
32803 if(this.hideEl !== false){
32804 this.boundEl.hide();
32807 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
32808 this.fixIEFocus = true;
32809 this.deferredFocus.defer(50, this);
32811 this.field.focus();
32813 this.fireEvent("startedit", this.boundEl, this.startValue);
32816 deferredFocus : function(){
32818 this.field.focus();
32823 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
32824 * reverted to the original starting value.
32825 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
32826 * cancel (defaults to false)
32828 cancelEdit : function(remainVisible){
32830 this.setValue(this.startValue);
32831 if(remainVisible !== true){
32838 onBlur : function(){
32839 if(this.allowBlur !== true && this.editing){
32840 this.completeEdit();
32845 onHide : function(){
32847 this.completeEdit();
32851 if(this.field.collapse){
32852 this.field.collapse();
32855 if(this.hideEl !== false){
32856 this.boundEl.show();
32859 Roo.QuickTips.enable();
32864 * Sets the data value of the editor
32865 * @param {Mixed} value Any valid value supported by the underlying field
32867 setValue : function(v){
32868 this.field.setValue(v);
32872 * Gets the data value of the editor
32873 * @return {Mixed} The data value
32875 getValue : function(){
32876 return this.field.getValue();
32880 * Ext JS Library 1.1.1
32881 * Copyright(c) 2006-2007, Ext JS, LLC.
32883 * Originally Released Under LGPL - original licence link has changed is not relivant.
32886 * <script type="text/javascript">
32890 * @class Roo.BasicDialog
32891 * @extends Roo.util.Observable
32892 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32894 var dlg = new Roo.BasicDialog("my-dlg", {
32903 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32904 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32905 dlg.addButton('Cancel', dlg.hide, dlg);
32908 <b>A Dialog should always be a direct child of the body element.</b>
32909 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32910 * @cfg {String} title Default text to display in the title bar (defaults to null)
32911 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32912 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32913 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32914 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32915 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32916 * (defaults to null with no animation)
32917 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32918 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32919 * property for valid values (defaults to 'all')
32920 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32921 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32922 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32923 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32924 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32925 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32926 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32927 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32928 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32929 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32930 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32931 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32932 * draggable = true (defaults to false)
32933 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32934 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32935 * shadow (defaults to false)
32936 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32937 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32938 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32939 * @cfg {Array} buttons Array of buttons
32940 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32942 * Create a new BasicDialog.
32943 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32944 * @param {Object} config Configuration options
32946 Roo.BasicDialog = function(el, config){
32947 this.el = Roo.get(el);
32948 var dh = Roo.DomHelper;
32949 if(!this.el && config && config.autoCreate){
32950 if(typeof config.autoCreate == "object"){
32951 if(!config.autoCreate.id){
32952 config.autoCreate.id = el;
32954 this.el = dh.append(document.body,
32955 config.autoCreate, true);
32957 this.el = dh.append(document.body,
32958 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32962 el.setDisplayed(true);
32963 el.hide = this.hideAction;
32965 el.addClass("x-dlg");
32967 Roo.apply(this, config);
32969 this.proxy = el.createProxy("x-dlg-proxy");
32970 this.proxy.hide = this.hideAction;
32971 this.proxy.setOpacity(.5);
32975 el.setWidth(config.width);
32978 el.setHeight(config.height);
32980 this.size = el.getSize();
32981 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32982 this.xy = [config.x,config.y];
32984 this.xy = el.getCenterXY(true);
32986 /** The header element @type Roo.Element */
32987 this.header = el.child("> .x-dlg-hd");
32988 /** The body element @type Roo.Element */
32989 this.body = el.child("> .x-dlg-bd");
32990 /** The footer element @type Roo.Element */
32991 this.footer = el.child("> .x-dlg-ft");
32994 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32997 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
33000 this.header.unselectable();
33002 this.header.update(this.title);
33004 // this element allows the dialog to be focused for keyboard event
33005 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
33006 this.focusEl.swallowEvent("click", true);
33008 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
33010 // wrap the body and footer for special rendering
33011 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
33013 this.bwrap.dom.appendChild(this.footer.dom);
33016 this.bg = this.el.createChild({
33017 tag: "div", cls:"x-dlg-bg",
33018 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
33020 this.centerBg = this.bg.child("div.x-dlg-bg-center");
33023 if(this.autoScroll !== false && !this.autoTabs){
33024 this.body.setStyle("overflow", "auto");
33027 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
33029 if(this.closable !== false){
33030 this.el.addClass("x-dlg-closable");
33031 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
33032 this.close.on("click", this.closeClick, this);
33033 this.close.addClassOnOver("x-dlg-close-over");
33035 if(this.collapsible !== false){
33036 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
33037 this.collapseBtn.on("click", this.collapseClick, this);
33038 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
33039 this.header.on("dblclick", this.collapseClick, this);
33041 if(this.resizable !== false){
33042 this.el.addClass("x-dlg-resizable");
33043 this.resizer = new Roo.Resizable(el, {
33044 minWidth: this.minWidth || 80,
33045 minHeight:this.minHeight || 80,
33046 handles: this.resizeHandles || "all",
33049 this.resizer.on("beforeresize", this.beforeResize, this);
33050 this.resizer.on("resize", this.onResize, this);
33052 if(this.draggable !== false){
33053 el.addClass("x-dlg-draggable");
33054 if (!this.proxyDrag) {
33055 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
33058 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
33060 dd.setHandleElId(this.header.id);
33061 dd.endDrag = this.endMove.createDelegate(this);
33062 dd.startDrag = this.startMove.createDelegate(this);
33063 dd.onDrag = this.onDrag.createDelegate(this);
33068 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
33069 this.mask.enableDisplayMode("block");
33071 this.el.addClass("x-dlg-modal");
33074 this.shadow = new Roo.Shadow({
33075 mode : typeof this.shadow == "string" ? this.shadow : "sides",
33076 offset : this.shadowOffset
33079 this.shadowOffset = 0;
33081 if(Roo.useShims && this.shim !== false){
33082 this.shim = this.el.createShim();
33083 this.shim.hide = this.hideAction;
33091 if (this.buttons) {
33092 var bts= this.buttons;
33094 Roo.each(bts, function(b) {
33103 * Fires when a key is pressed
33104 * @param {Roo.BasicDialog} this
33105 * @param {Roo.EventObject} e
33110 * Fires when this dialog is moved by the user.
33111 * @param {Roo.BasicDialog} this
33112 * @param {Number} x The new page X
33113 * @param {Number} y The new page Y
33118 * Fires when this dialog is resized by the user.
33119 * @param {Roo.BasicDialog} this
33120 * @param {Number} width The new width
33121 * @param {Number} height The new height
33125 * @event beforehide
33126 * Fires before this dialog is hidden.
33127 * @param {Roo.BasicDialog} this
33129 "beforehide" : true,
33132 * Fires when this dialog is hidden.
33133 * @param {Roo.BasicDialog} this
33137 * @event beforeshow
33138 * Fires before this dialog is shown.
33139 * @param {Roo.BasicDialog} this
33141 "beforeshow" : true,
33144 * Fires when this dialog is shown.
33145 * @param {Roo.BasicDialog} this
33149 el.on("keydown", this.onKeyDown, this);
33150 el.on("mousedown", this.toFront, this);
33151 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
33153 Roo.DialogManager.register(this);
33154 Roo.BasicDialog.superclass.constructor.call(this);
33157 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
33158 shadowOffset: Roo.isIE ? 6 : 5,
33161 minButtonWidth: 75,
33162 defaultButton: null,
33163 buttonAlign: "right",
33168 * Sets the dialog title text
33169 * @param {String} text The title text to display
33170 * @return {Roo.BasicDialog} this
33172 setTitle : function(text){
33173 this.header.update(text);
33178 closeClick : function(){
33183 collapseClick : function(){
33184 this[this.collapsed ? "expand" : "collapse"]();
33188 * Collapses the dialog to its minimized state (only the title bar is visible).
33189 * Equivalent to the user clicking the collapse dialog button.
33191 collapse : function(){
33192 if(!this.collapsed){
33193 this.collapsed = true;
33194 this.el.addClass("x-dlg-collapsed");
33195 this.restoreHeight = this.el.getHeight();
33196 this.resizeTo(this.el.getWidth(), this.header.getHeight());
33201 * Expands a collapsed dialog back to its normal state. Equivalent to the user
33202 * clicking the expand dialog button.
33204 expand : function(){
33205 if(this.collapsed){
33206 this.collapsed = false;
33207 this.el.removeClass("x-dlg-collapsed");
33208 this.resizeTo(this.el.getWidth(), this.restoreHeight);
33213 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
33214 * @return {Roo.TabPanel} The tabs component
33216 initTabs : function(){
33217 var tabs = this.getTabs();
33218 while(tabs.getTab(0)){
33221 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
33223 tabs.addTab(Roo.id(dom), dom.title);
33231 beforeResize : function(){
33232 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
33236 onResize : function(){
33237 this.refreshSize();
33238 this.syncBodyHeight();
33239 this.adjustAssets();
33241 this.fireEvent("resize", this, this.size.width, this.size.height);
33245 onKeyDown : function(e){
33246 if(this.isVisible()){
33247 this.fireEvent("keydown", this, e);
33252 * Resizes the dialog.
33253 * @param {Number} width
33254 * @param {Number} height
33255 * @return {Roo.BasicDialog} this
33257 resizeTo : function(width, height){
33258 this.el.setSize(width, height);
33259 this.size = {width: width, height: height};
33260 this.syncBodyHeight();
33261 if(this.fixedcenter){
33264 if(this.isVisible()){
33265 this.constrainXY();
33266 this.adjustAssets();
33268 this.fireEvent("resize", this, width, height);
33274 * Resizes the dialog to fit the specified content size.
33275 * @param {Number} width
33276 * @param {Number} height
33277 * @return {Roo.BasicDialog} this
33279 setContentSize : function(w, h){
33280 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
33281 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
33282 //if(!this.el.isBorderBox()){
33283 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
33284 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
33287 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
33288 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
33290 this.resizeTo(w, h);
33295 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
33296 * executed in response to a particular key being pressed while the dialog is active.
33297 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
33298 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
33299 * @param {Function} fn The function to call
33300 * @param {Object} scope (optional) The scope of the function
33301 * @return {Roo.BasicDialog} this
33303 addKeyListener : function(key, fn, scope){
33304 var keyCode, shift, ctrl, alt;
33305 if(typeof key == "object" && !(key instanceof Array)){
33306 keyCode = key["key"];
33307 shift = key["shift"];
33308 ctrl = key["ctrl"];
33313 var handler = function(dlg, e){
33314 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
33315 var k = e.getKey();
33316 if(keyCode instanceof Array){
33317 for(var i = 0, len = keyCode.length; i < len; i++){
33318 if(keyCode[i] == k){
33319 fn.call(scope || window, dlg, k, e);
33325 fn.call(scope || window, dlg, k, e);
33330 this.on("keydown", handler);
33335 * Returns the TabPanel component (creates it if it doesn't exist).
33336 * Note: If you wish to simply check for the existence of tabs without creating them,
33337 * check for a null 'tabs' property.
33338 * @return {Roo.TabPanel} The tabs component
33340 getTabs : function(){
33342 this.el.addClass("x-dlg-auto-tabs");
33343 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
33344 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
33350 * Adds a button to the footer section of the dialog.
33351 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
33352 * object or a valid Roo.DomHelper element config
33353 * @param {Function} handler The function called when the button is clicked
33354 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
33355 * @return {Roo.Button} The new button
33357 addButton : function(config, handler, scope){
33358 var dh = Roo.DomHelper;
33360 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
33362 if(!this.btnContainer){
33363 var tb = this.footer.createChild({
33365 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
33366 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
33368 this.btnContainer = tb.firstChild.firstChild.firstChild;
33373 minWidth: this.minButtonWidth,
33376 if(typeof config == "string"){
33377 bconfig.text = config;
33380 bconfig.dhconfig = config;
33382 Roo.apply(bconfig, config);
33386 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
33387 bconfig.position = Math.max(0, bconfig.position);
33388 fc = this.btnContainer.childNodes[bconfig.position];
33391 var btn = new Roo.Button(
33393 this.btnContainer.insertBefore(document.createElement("td"),fc)
33394 : this.btnContainer.appendChild(document.createElement("td")),
33395 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
33398 this.syncBodyHeight();
33401 * Array of all the buttons that have been added to this dialog via addButton
33406 this.buttons.push(btn);
33411 * Sets the default button to be focused when the dialog is displayed.
33412 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
33413 * @return {Roo.BasicDialog} this
33415 setDefaultButton : function(btn){
33416 this.defaultButton = btn;
33421 getHeaderFooterHeight : function(safe){
33424 height += this.header.getHeight();
33427 var fm = this.footer.getMargins();
33428 height += (this.footer.getHeight()+fm.top+fm.bottom);
33430 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
33431 height += this.centerBg.getPadding("tb");
33436 syncBodyHeight : function()
33438 var bd = this.body, // the text
33439 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
33441 var height = this.size.height - this.getHeaderFooterHeight(false);
33442 bd.setHeight(height-bd.getMargins("tb"));
33443 var hh = this.header.getHeight();
33444 var h = this.size.height-hh;
33447 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
33448 bw.setHeight(h-cb.getPadding("tb"));
33450 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
33451 bd.setWidth(bw.getWidth(true));
33453 this.tabs.syncHeight();
33455 this.tabs.el.repaint();
33461 * Restores the previous state of the dialog if Roo.state is configured.
33462 * @return {Roo.BasicDialog} this
33464 restoreState : function(){
33465 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
33466 if(box && box.width){
33467 this.xy = [box.x, box.y];
33468 this.resizeTo(box.width, box.height);
33474 beforeShow : function(){
33476 if(this.fixedcenter){
33477 this.xy = this.el.getCenterXY(true);
33480 Roo.get(document.body).addClass("x-body-masked");
33481 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33484 this.constrainXY();
33488 animShow : function(){
33489 var b = Roo.get(this.animateTarget).getBox();
33490 this.proxy.setSize(b.width, b.height);
33491 this.proxy.setLocation(b.x, b.y);
33493 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
33494 true, .35, this.showEl.createDelegate(this));
33498 * Shows the dialog.
33499 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
33500 * @return {Roo.BasicDialog} this
33502 show : function(animateTarget){
33503 if (this.fireEvent("beforeshow", this) === false){
33506 if(this.syncHeightBeforeShow){
33507 this.syncBodyHeight();
33508 }else if(this.firstShow){
33509 this.firstShow = false;
33510 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
33512 this.animateTarget = animateTarget || this.animateTarget;
33513 if(!this.el.isVisible()){
33515 if(this.animateTarget && Roo.get(this.animateTarget)){
33525 showEl : function(){
33527 this.el.setXY(this.xy);
33529 this.adjustAssets(true);
33532 // IE peekaboo bug - fix found by Dave Fenwick
33536 this.fireEvent("show", this);
33540 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
33541 * dialog itself will receive focus.
33543 focus : function(){
33544 if(this.defaultButton){
33545 this.defaultButton.focus();
33547 this.focusEl.focus();
33552 constrainXY : function(){
33553 if(this.constraintoviewport !== false){
33554 if(!this.viewSize){
33555 if(this.container){
33556 var s = this.container.getSize();
33557 this.viewSize = [s.width, s.height];
33559 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
33562 var s = Roo.get(this.container||document).getScroll();
33564 var x = this.xy[0], y = this.xy[1];
33565 var w = this.size.width, h = this.size.height;
33566 var vw = this.viewSize[0], vh = this.viewSize[1];
33567 // only move it if it needs it
33569 // first validate right/bottom
33570 if(x + w > vw+s.left){
33574 if(y + h > vh+s.top){
33578 // then make sure top/left isn't negative
33590 if(this.isVisible()){
33591 this.el.setLocation(x, y);
33592 this.adjustAssets();
33599 onDrag : function(){
33600 if(!this.proxyDrag){
33601 this.xy = this.el.getXY();
33602 this.adjustAssets();
33607 adjustAssets : function(doShow){
33608 var x = this.xy[0], y = this.xy[1];
33609 var w = this.size.width, h = this.size.height;
33610 if(doShow === true){
33612 this.shadow.show(this.el);
33618 if(this.shadow && this.shadow.isVisible()){
33619 this.shadow.show(this.el);
33621 if(this.shim && this.shim.isVisible()){
33622 this.shim.setBounds(x, y, w, h);
33627 adjustViewport : function(w, h){
33629 w = Roo.lib.Dom.getViewWidth();
33630 h = Roo.lib.Dom.getViewHeight();
33633 this.viewSize = [w, h];
33634 if(this.modal && this.mask.isVisible()){
33635 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
33636 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33638 if(this.isVisible()){
33639 this.constrainXY();
33644 * Destroys this dialog and all its supporting elements (including any tabs, shim,
33645 * shadow, proxy, mask, etc.) Also removes all event listeners.
33646 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
33648 destroy : function(removeEl){
33649 if(this.isVisible()){
33650 this.animateTarget = null;
33653 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
33655 this.tabs.destroy(removeEl);
33668 for(var i = 0, len = this.buttons.length; i < len; i++){
33669 this.buttons[i].destroy();
33672 this.el.removeAllListeners();
33673 if(removeEl === true){
33674 this.el.update("");
33677 Roo.DialogManager.unregister(this);
33681 startMove : function(){
33682 if(this.proxyDrag){
33685 if(this.constraintoviewport !== false){
33686 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
33691 endMove : function(){
33692 if(!this.proxyDrag){
33693 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
33695 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
33698 this.refreshSize();
33699 this.adjustAssets();
33701 this.fireEvent("move", this, this.xy[0], this.xy[1]);
33705 * Brings this dialog to the front of any other visible dialogs
33706 * @return {Roo.BasicDialog} this
33708 toFront : function(){
33709 Roo.DialogManager.bringToFront(this);
33714 * Sends this dialog to the back (under) of any other visible dialogs
33715 * @return {Roo.BasicDialog} this
33717 toBack : function(){
33718 Roo.DialogManager.sendToBack(this);
33723 * Centers this dialog in the viewport
33724 * @return {Roo.BasicDialog} this
33726 center : function(){
33727 var xy = this.el.getCenterXY(true);
33728 this.moveTo(xy[0], xy[1]);
33733 * Moves the dialog's top-left corner to the specified point
33734 * @param {Number} x
33735 * @param {Number} y
33736 * @return {Roo.BasicDialog} this
33738 moveTo : function(x, y){
33740 if(this.isVisible()){
33741 this.el.setXY(this.xy);
33742 this.adjustAssets();
33748 * Aligns the dialog to the specified element
33749 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33750 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
33751 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33752 * @return {Roo.BasicDialog} this
33754 alignTo : function(element, position, offsets){
33755 this.xy = this.el.getAlignToXY(element, position, offsets);
33756 if(this.isVisible()){
33757 this.el.setXY(this.xy);
33758 this.adjustAssets();
33764 * Anchors an element to another element and realigns it when the window is resized.
33765 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33766 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
33767 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33768 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
33769 * is a number, it is used as the buffer delay (defaults to 50ms).
33770 * @return {Roo.BasicDialog} this
33772 anchorTo : function(el, alignment, offsets, monitorScroll){
33773 var action = function(){
33774 this.alignTo(el, alignment, offsets);
33776 Roo.EventManager.onWindowResize(action, this);
33777 var tm = typeof monitorScroll;
33778 if(tm != 'undefined'){
33779 Roo.EventManager.on(window, 'scroll', action, this,
33780 {buffer: tm == 'number' ? monitorScroll : 50});
33787 * Returns true if the dialog is visible
33788 * @return {Boolean}
33790 isVisible : function(){
33791 return this.el.isVisible();
33795 animHide : function(callback){
33796 var b = Roo.get(this.animateTarget).getBox();
33798 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
33800 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
33801 this.hideEl.createDelegate(this, [callback]));
33805 * Hides the dialog.
33806 * @param {Function} callback (optional) Function to call when the dialog is hidden
33807 * @return {Roo.BasicDialog} this
33809 hide : function(callback){
33810 if (this.fireEvent("beforehide", this) === false){
33814 this.shadow.hide();
33819 // sometimes animateTarget seems to get set.. causing problems...
33820 // this just double checks..
33821 if(this.animateTarget && Roo.get(this.animateTarget)) {
33822 this.animHide(callback);
33825 this.hideEl(callback);
33831 hideEl : function(callback){
33835 Roo.get(document.body).removeClass("x-body-masked");
33837 this.fireEvent("hide", this);
33838 if(typeof callback == "function"){
33844 hideAction : function(){
33845 this.setLeft("-10000px");
33846 this.setTop("-10000px");
33847 this.setStyle("visibility", "hidden");
33851 refreshSize : function(){
33852 this.size = this.el.getSize();
33853 this.xy = this.el.getXY();
33854 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
33858 // z-index is managed by the DialogManager and may be overwritten at any time
33859 setZIndex : function(index){
33861 this.mask.setStyle("z-index", index);
33864 this.shim.setStyle("z-index", ++index);
33867 this.shadow.setZIndex(++index);
33869 this.el.setStyle("z-index", ++index);
33871 this.proxy.setStyle("z-index", ++index);
33874 this.resizer.proxy.setStyle("z-index", ++index);
33877 this.lastZIndex = index;
33881 * Returns the element for this dialog
33882 * @return {Roo.Element} The underlying dialog Element
33884 getEl : function(){
33890 * @class Roo.DialogManager
33891 * Provides global access to BasicDialogs that have been created and
33892 * support for z-indexing (layering) multiple open dialogs.
33894 Roo.DialogManager = function(){
33896 var accessList = [];
33900 var sortDialogs = function(d1, d2){
33901 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33905 var orderDialogs = function(){
33906 accessList.sort(sortDialogs);
33907 var seed = Roo.DialogManager.zseed;
33908 for(var i = 0, len = accessList.length; i < len; i++){
33909 var dlg = accessList[i];
33911 dlg.setZIndex(seed + (i*10));
33918 * The starting z-index for BasicDialogs (defaults to 9000)
33919 * @type Number The z-index value
33924 register : function(dlg){
33925 list[dlg.id] = dlg;
33926 accessList.push(dlg);
33930 unregister : function(dlg){
33931 delete list[dlg.id];
33934 if(!accessList.indexOf){
33935 for( i = 0, len = accessList.length; i < len; i++){
33936 if(accessList[i] == dlg){
33937 accessList.splice(i, 1);
33942 i = accessList.indexOf(dlg);
33944 accessList.splice(i, 1);
33950 * Gets a registered dialog by id
33951 * @param {String/Object} id The id of the dialog or a dialog
33952 * @return {Roo.BasicDialog} this
33954 get : function(id){
33955 return typeof id == "object" ? id : list[id];
33959 * Brings the specified dialog to the front
33960 * @param {String/Object} dlg The id of the dialog or a dialog
33961 * @return {Roo.BasicDialog} this
33963 bringToFront : function(dlg){
33964 dlg = this.get(dlg);
33967 dlg._lastAccess = new Date().getTime();
33974 * Sends the specified dialog to the back
33975 * @param {String/Object} dlg The id of the dialog or a dialog
33976 * @return {Roo.BasicDialog} this
33978 sendToBack : function(dlg){
33979 dlg = this.get(dlg);
33980 dlg._lastAccess = -(new Date().getTime());
33986 * Hides all dialogs
33988 hideAll : function(){
33989 for(var id in list){
33990 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33999 * @class Roo.LayoutDialog
34000 * @extends Roo.BasicDialog
34001 * @children Roo.ContentPanel
34002 * @parent builder none
34003 * Dialog which provides adjustments for working with a layout in a Dialog.
34004 * Add your necessary layout config options to the dialog's config.<br>
34005 * Example usage (including a nested layout):
34008 dialog = new Roo.LayoutDialog("download-dlg", {
34017 // layout config merges with the dialog config
34019 tabPosition: "top",
34020 alwaysShowTabs: true
34023 dialog.addKeyListener(27, dialog.hide, dialog);
34024 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
34025 dialog.addButton("Build It!", this.getDownload, this);
34027 // we can even add nested layouts
34028 var innerLayout = new Roo.BorderLayout("dl-inner", {
34038 innerLayout.beginUpdate();
34039 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
34040 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
34041 innerLayout.endUpdate(true);
34043 var layout = dialog.getLayout();
34044 layout.beginUpdate();
34045 layout.add("center", new Roo.ContentPanel("standard-panel",
34046 {title: "Download the Source", fitToFrame:true}));
34047 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
34048 {title: "Build your own roo.js"}));
34049 layout.getRegion("center").showPanel(sp);
34050 layout.endUpdate();
34054 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
34055 * @param {Object} config configuration options
34057 Roo.LayoutDialog = function(el, cfg){
34060 if (typeof(cfg) == 'undefined') {
34061 config = Roo.apply({}, el);
34062 // not sure why we use documentElement here.. - it should always be body.
34063 // IE7 borks horribly if we use documentElement.
34064 // webkit also does not like documentElement - it creates a body element...
34065 el = Roo.get( document.body || document.documentElement ).createChild();
34066 //config.autoCreate = true;
34070 config.autoTabs = false;
34071 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
34072 this.body.setStyle({overflow:"hidden", position:"relative"});
34073 this.layout = new Roo.BorderLayout(this.body.dom, config);
34074 this.layout.monitorWindowResize = false;
34075 this.el.addClass("x-dlg-auto-layout");
34076 // fix case when center region overwrites center function
34077 this.center = Roo.BasicDialog.prototype.center;
34078 this.on("show", this.layout.layout, this.layout, true);
34079 if (config.items) {
34080 var xitems = config.items;
34081 delete config.items;
34082 Roo.each(xitems, this.addxtype, this);
34087 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
34091 * @cfg {Roo.LayoutRegion} east
34094 * @cfg {Roo.LayoutRegion} west
34097 * @cfg {Roo.LayoutRegion} south
34100 * @cfg {Roo.LayoutRegion} north
34103 * @cfg {Roo.LayoutRegion} center
34106 * @cfg {Roo.Button} buttons[] Bottom buttons..
34111 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
34114 endUpdate : function(){
34115 this.layout.endUpdate();
34119 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
34122 beginUpdate : function(){
34123 this.layout.beginUpdate();
34127 * Get the BorderLayout for this dialog
34128 * @return {Roo.BorderLayout}
34130 getLayout : function(){
34131 return this.layout;
34134 showEl : function(){
34135 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
34137 this.layout.layout();
34142 // Use the syncHeightBeforeShow config option to control this automatically
34143 syncBodyHeight : function(){
34144 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
34145 if(this.layout){this.layout.layout();}
34149 * Add an xtype element (actually adds to the layout.)
34150 * @return {Object} xdata xtype object data.
34153 addxtype : function(c) {
34154 return this.layout.addxtype(c);
34158 * Ext JS Library 1.1.1
34159 * Copyright(c) 2006-2007, Ext JS, LLC.
34161 * Originally Released Under LGPL - original licence link has changed is not relivant.
34164 * <script type="text/javascript">
34168 * @class Roo.MessageBox
34169 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
34173 Roo.Msg.alert('Status', 'Changes saved successfully.');
34175 // Prompt for user data:
34176 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
34178 // process text value...
34182 // Show a dialog using config options:
34184 title:'Save Changes?',
34185 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
34186 buttons: Roo.Msg.YESNOCANCEL,
34193 Roo.MessageBox = function(){
34194 var dlg, opt, mask, waitTimer;
34195 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
34196 var buttons, activeTextEl, bwidth;
34199 var handleButton = function(button){
34201 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
34205 var handleHide = function(){
34206 if(opt && opt.cls){
34207 dlg.el.removeClass(opt.cls);
34210 Roo.TaskMgr.stop(waitTimer);
34216 var updateButtons = function(b){
34219 buttons["ok"].hide();
34220 buttons["cancel"].hide();
34221 buttons["yes"].hide();
34222 buttons["no"].hide();
34223 dlg.footer.dom.style.display = 'none';
34226 dlg.footer.dom.style.display = '';
34227 for(var k in buttons){
34228 if(typeof buttons[k] != "function"){
34231 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
34232 width += buttons[k].el.getWidth()+15;
34242 var handleEsc = function(d, k, e){
34243 if(opt && opt.closable !== false){
34253 * Returns a reference to the underlying {@link Roo.BasicDialog} element
34254 * @return {Roo.BasicDialog} The BasicDialog element
34256 getDialog : function(){
34258 dlg = new Roo.BasicDialog("x-msg-box", {
34263 constraintoviewport:false,
34265 collapsible : false,
34268 width:400, height:100,
34269 buttonAlign:"center",
34270 closeClick : function(){
34271 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
34272 handleButton("no");
34274 handleButton("cancel");
34278 dlg.on("hide", handleHide);
34280 dlg.addKeyListener(27, handleEsc);
34282 var bt = this.buttonText;
34283 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
34284 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
34285 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
34286 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
34287 bodyEl = dlg.body.createChild({
34289 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>'
34291 msgEl = bodyEl.dom.firstChild;
34292 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
34293 textboxEl.enableDisplayMode();
34294 textboxEl.addKeyListener([10,13], function(){
34295 if(dlg.isVisible() && opt && opt.buttons){
34296 if(opt.buttons.ok){
34297 handleButton("ok");
34298 }else if(opt.buttons.yes){
34299 handleButton("yes");
34303 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
34304 textareaEl.enableDisplayMode();
34305 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
34306 progressEl.enableDisplayMode();
34307 var pf = progressEl.dom.firstChild;
34309 pp = Roo.get(pf.firstChild);
34310 pp.setHeight(pf.offsetHeight);
34318 * Updates the message box body text
34319 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
34320 * the XHTML-compliant non-breaking space character '&#160;')
34321 * @return {Roo.MessageBox} This message box
34323 updateText : function(text){
34324 if(!dlg.isVisible() && !opt.width){
34325 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
34327 msgEl.innerHTML = text || ' ';
34329 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
34330 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
34332 Math.min(opt.width || cw , this.maxWidth),
34333 Math.max(opt.minWidth || this.minWidth, bwidth)
34336 activeTextEl.setWidth(w);
34338 if(dlg.isVisible()){
34339 dlg.fixedcenter = false;
34341 // to big, make it scroll. = But as usual stupid IE does not support
34344 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
34345 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
34346 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
34348 bodyEl.dom.style.height = '';
34349 bodyEl.dom.style.overflowY = '';
34352 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
34354 bodyEl.dom.style.overflowX = '';
34357 dlg.setContentSize(w, bodyEl.getHeight());
34358 if(dlg.isVisible()){
34359 dlg.fixedcenter = true;
34365 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
34366 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
34367 * @param {Number} value Any number between 0 and 1 (e.g., .5)
34368 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
34369 * @return {Roo.MessageBox} This message box
34371 updateProgress : function(value, text){
34373 this.updateText(text);
34375 if (pp) { // weird bug on my firefox - for some reason this is not defined
34376 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
34382 * Returns true if the message box is currently displayed
34383 * @return {Boolean} True if the message box is visible, else false
34385 isVisible : function(){
34386 return dlg && dlg.isVisible();
34390 * Hides the message box if it is displayed
34393 if(this.isVisible()){
34399 * Displays a new message box, or reinitializes an existing message box, based on the config options
34400 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
34401 * The following config object properties are supported:
34403 Property Type Description
34404 ---------- --------------- ------------------------------------------------------------------------------------
34405 animEl String/Element An id or Element from which the message box should animate as it opens and
34406 closes (defaults to undefined)
34407 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
34408 cancel:'Bar'}), or false to not show any buttons (defaults to false)
34409 closable Boolean False to hide the top-right close button (defaults to true). Note that
34410 progress and wait dialogs will ignore this property and always hide the
34411 close button as they can only be closed programmatically.
34412 cls String A custom CSS class to apply to the message box element
34413 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
34414 displayed (defaults to 75)
34415 fn Function A callback function to execute after closing the dialog. The arguments to the
34416 function will be btn (the name of the button that was clicked, if applicable,
34417 e.g. "ok"), and text (the value of the active text field, if applicable).
34418 Progress and wait dialogs will ignore this option since they do not respond to
34419 user actions and can only be closed programmatically, so any required function
34420 should be called by the same code after it closes the dialog.
34421 icon String A CSS class that provides a background image to be used as an icon for
34422 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
34423 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
34424 minWidth Number The minimum width in pixels of the message box (defaults to 100)
34425 modal Boolean False to allow user interaction with the page while the message box is
34426 displayed (defaults to true)
34427 msg String A string that will replace the existing message box body text (defaults
34428 to the XHTML-compliant non-breaking space character ' ')
34429 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
34430 progress Boolean True to display a progress bar (defaults to false)
34431 progressText String The text to display inside the progress bar if progress = true (defaults to '')
34432 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
34433 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
34434 title String The title text
34435 value String The string value to set into the active textbox element if displayed
34436 wait Boolean True to display a progress bar (defaults to false)
34437 width Number The width of the dialog in pixels
34444 msg: 'Please enter your address:',
34446 buttons: Roo.MessageBox.OKCANCEL,
34449 animEl: 'addAddressBtn'
34452 * @param {Object} config Configuration options
34453 * @return {Roo.MessageBox} This message box
34455 show : function(options)
34458 // this causes nightmares if you show one dialog after another
34459 // especially on callbacks..
34461 if(this.isVisible()){
34464 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
34465 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
34466 Roo.log("New Dialog Message:" + options.msg )
34467 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
34468 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
34471 var d = this.getDialog();
34473 d.setTitle(opt.title || " ");
34474 d.close.setDisplayed(opt.closable !== false);
34475 activeTextEl = textboxEl;
34476 opt.prompt = opt.prompt || (opt.multiline ? true : false);
34481 textareaEl.setHeight(typeof opt.multiline == "number" ?
34482 opt.multiline : this.defaultTextHeight);
34483 activeTextEl = textareaEl;
34492 progressEl.setDisplayed(opt.progress === true);
34493 this.updateProgress(0);
34494 activeTextEl.dom.value = opt.value || "";
34496 dlg.setDefaultButton(activeTextEl);
34498 var bs = opt.buttons;
34501 db = buttons["ok"];
34502 }else if(bs && bs.yes){
34503 db = buttons["yes"];
34505 dlg.setDefaultButton(db);
34507 bwidth = updateButtons(opt.buttons);
34508 this.updateText(opt.msg);
34510 d.el.addClass(opt.cls);
34512 d.proxyDrag = opt.proxyDrag === true;
34513 d.modal = opt.modal !== false;
34514 d.mask = opt.modal !== false ? mask : false;
34515 if(!d.isVisible()){
34516 // force it to the end of the z-index stack so it gets a cursor in FF
34517 document.body.appendChild(dlg.el.dom);
34518 d.animateTarget = null;
34519 d.show(options.animEl);
34525 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
34526 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
34527 * and closing the message box when the process is complete.
34528 * @param {String} title The title bar text
34529 * @param {String} msg The message box body text
34530 * @return {Roo.MessageBox} This message box
34532 progress : function(title, msg){
34539 minWidth: this.minProgressWidth,
34546 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
34547 * If a callback function is passed it will be called after the user clicks the button, and the
34548 * id of the button that was clicked will be passed as the only parameter to the callback
34549 * (could also be the top-right close button).
34550 * @param {String} title The title bar text
34551 * @param {String} msg The message box body text
34552 * @param {Function} fn (optional) The callback function invoked after the message box is closed
34553 * @param {Object} scope (optional) The scope of the callback function
34554 * @return {Roo.MessageBox} This message box
34556 alert : function(title, msg, fn, scope){
34569 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
34570 * interaction while waiting for a long-running process to complete that does not have defined intervals.
34571 * You are responsible for closing the message box when the process is complete.
34572 * @param {String} msg The message box body text
34573 * @param {String} title (optional) The title bar text
34574 * @return {Roo.MessageBox} This message box
34576 wait : function(msg, title){
34587 waitTimer = Roo.TaskMgr.start({
34589 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
34597 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
34598 * If a callback function is passed it will be called after the user clicks either button, and the id of the
34599 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
34600 * @param {String} title The title bar text
34601 * @param {String} msg The message box body text
34602 * @param {Function} fn (optional) The callback function invoked after the message box is closed
34603 * @param {Object} scope (optional) The scope of the callback function
34604 * @return {Roo.MessageBox} This message box
34606 confirm : function(title, msg, fn, scope){
34610 buttons: this.YESNO,
34619 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
34620 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
34621 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
34622 * (could also be the top-right close button) and the text that was entered will be passed as the two
34623 * parameters to the callback.
34624 * @param {String} title The title bar text
34625 * @param {String} msg The message box body text
34626 * @param {Function} fn (optional) The callback function invoked after the message box is closed
34627 * @param {Object} scope (optional) The scope of the callback function
34628 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
34629 * property, or the height in pixels to create the textbox (defaults to false / single-line)
34630 * @return {Roo.MessageBox} This message box
34632 prompt : function(title, msg, fn, scope, multiline){
34636 buttons: this.OKCANCEL,
34641 multiline: multiline,
34648 * Button config that displays a single OK button
34653 * Button config that displays Yes and No buttons
34656 YESNO : {yes:true, no:true},
34658 * Button config that displays OK and Cancel buttons
34661 OKCANCEL : {ok:true, cancel:true},
34663 * Button config that displays Yes, No and Cancel buttons
34666 YESNOCANCEL : {yes:true, no:true, cancel:true},
34669 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
34672 defaultTextHeight : 75,
34674 * The maximum width in pixels of the message box (defaults to 600)
34679 * The minimum width in pixels of the message box (defaults to 100)
34684 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
34685 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
34688 minProgressWidth : 250,
34690 * An object containing the default button text strings that can be overriden for localized language support.
34691 * Supported properties are: ok, cancel, yes and no.
34692 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
34705 * Shorthand for {@link Roo.MessageBox}
34707 Roo.Msg = Roo.MessageBox;/*
34709 * Ext JS Library 1.1.1
34710 * Copyright(c) 2006-2007, Ext JS, LLC.
34712 * Originally Released Under LGPL - original licence link has changed is not relivant.
34715 * <script type="text/javascript">
34718 * @class Roo.QuickTips
34719 * Provides attractive and customizable tooltips for any element.
34722 Roo.QuickTips = function(){
34723 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
34724 var ce, bd, xy, dd;
34725 var visible = false, disabled = true, inited = false;
34726 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
34728 var onOver = function(e){
34732 var t = e.getTarget();
34733 if(!t || t.nodeType !== 1 || t == document || t == document.body){
34736 if(ce && t == ce.el){
34737 clearTimeout(hideProc);
34740 if(t && tagEls[t.id]){
34741 tagEls[t.id].el = t;
34742 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
34745 var ttp, et = Roo.fly(t);
34746 var ns = cfg.namespace;
34747 if(tm.interceptTitles && t.title){
34750 t.removeAttribute("title");
34751 e.preventDefault();
34753 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
34756 showProc = show.defer(tm.showDelay, tm, [{
34758 text: ttp.replace(/\\n/g,'<br/>'),
34759 width: et.getAttributeNS(ns, cfg.width),
34760 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
34761 title: et.getAttributeNS(ns, cfg.title),
34762 cls: et.getAttributeNS(ns, cfg.cls)
34767 var onOut = function(e){
34768 clearTimeout(showProc);
34769 var t = e.getTarget();
34770 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
34771 hideProc = setTimeout(hide, tm.hideDelay);
34775 var onMove = function(e){
34781 if(tm.trackMouse && ce){
34786 var onDown = function(e){
34787 clearTimeout(showProc);
34788 clearTimeout(hideProc);
34790 if(tm.hideOnClick){
34793 tm.enable.defer(100, tm);
34798 var getPad = function(){
34799 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
34802 var show = function(o){
34806 clearTimeout(dismissProc);
34808 if(removeCls){ // in case manually hidden
34809 el.removeClass(removeCls);
34813 el.addClass(ce.cls);
34814 removeCls = ce.cls;
34817 tipTitle.update(ce.title);
34820 tipTitle.update('');
34823 el.dom.style.width = tm.maxWidth+'px';
34824 //tipBody.dom.style.width = '';
34825 tipBodyText.update(o.text);
34826 var p = getPad(), w = ce.width;
34828 var td = tipBodyText.dom;
34829 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
34830 if(aw > tm.maxWidth){
34832 }else if(aw < tm.minWidth){
34838 //tipBody.setWidth(w);
34839 el.setWidth(parseInt(w, 10) + p);
34840 if(ce.autoHide === false){
34841 close.setDisplayed(true);
34846 close.setDisplayed(false);
34852 el.avoidY = xy[1]-18;
34857 el.setStyle("visibility", "visible");
34858 el.fadeIn({callback: afterShow});
34864 var afterShow = function(){
34868 if(tm.autoDismiss && ce.autoHide !== false){
34869 dismissProc = setTimeout(hide, tm.autoDismissDelay);
34874 var hide = function(noanim){
34875 clearTimeout(dismissProc);
34876 clearTimeout(hideProc);
34878 if(el.isVisible()){
34880 if(noanim !== true && tm.animate){
34881 el.fadeOut({callback: afterHide});
34888 var afterHide = function(){
34891 el.removeClass(removeCls);
34898 * @cfg {Number} minWidth
34899 * The minimum width of the quick tip (defaults to 40)
34903 * @cfg {Number} maxWidth
34904 * The maximum width of the quick tip (defaults to 300)
34908 * @cfg {Boolean} interceptTitles
34909 * True to automatically use the element's DOM title value if available (defaults to false)
34911 interceptTitles : false,
34913 * @cfg {Boolean} trackMouse
34914 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34916 trackMouse : false,
34918 * @cfg {Boolean} hideOnClick
34919 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34921 hideOnClick : true,
34923 * @cfg {Number} showDelay
34924 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
34928 * @cfg {Number} hideDelay
34929 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34933 * @cfg {Boolean} autoHide
34934 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34935 * Used in conjunction with hideDelay.
34940 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34941 * (defaults to true). Used in conjunction with autoDismissDelay.
34943 autoDismiss : true,
34946 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34948 autoDismissDelay : 5000,
34950 * @cfg {Boolean} animate
34951 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34956 * @cfg {String} title
34957 * Title text to display (defaults to ''). This can be any valid HTML markup.
34961 * @cfg {String} text
34962 * Body text to display (defaults to ''). This can be any valid HTML markup.
34966 * @cfg {String} cls
34967 * A CSS class to apply to the base quick tip element (defaults to '').
34971 * @cfg {Number} width
34972 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34973 * minWidth or maxWidth.
34978 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34979 * or display QuickTips in a page.
34982 tm = Roo.QuickTips;
34983 cfg = tm.tagConfig;
34985 if(!Roo.isReady){ // allow calling of init() before onReady
34986 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34989 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34990 el.fxDefaults = {stopFx: true};
34991 // maximum custom styling
34992 //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>');
34993 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>');
34994 tipTitle = el.child('h3');
34995 tipTitle.enableDisplayMode("block");
34996 tipBody = el.child('div.x-tip-bd');
34997 tipBodyText = el.child('div.x-tip-bd-inner');
34998 //bdLeft = el.child('div.x-tip-bd-left');
34999 //bdRight = el.child('div.x-tip-bd-right');
35000 close = el.child('div.x-tip-close');
35001 close.enableDisplayMode("block");
35002 close.on("click", hide);
35003 var d = Roo.get(document);
35004 d.on("mousedown", onDown);
35005 d.on("mouseover", onOver);
35006 d.on("mouseout", onOut);
35007 d.on("mousemove", onMove);
35008 esc = d.addKeyListener(27, hide);
35011 dd = el.initDD("default", null, {
35012 onDrag : function(){
35016 dd.setHandleElId(tipTitle.id);
35025 * Configures a new quick tip instance and assigns it to a target element. The following config options
35028 Property Type Description
35029 ---------- --------------------- ------------------------------------------------------------------------
35030 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
35032 * @param {Object} config The config object
35034 register : function(config){
35035 var cs = config instanceof Array ? config : arguments;
35036 for(var i = 0, len = cs.length; i < len; i++) {
35038 var target = c.target;
35040 if(target instanceof Array){
35041 for(var j = 0, jlen = target.length; j < jlen; j++){
35042 tagEls[target[j]] = c;
35045 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
35052 * Removes this quick tip from its element and destroys it.
35053 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
35055 unregister : function(el){
35056 delete tagEls[Roo.id(el)];
35060 * Enable this quick tip.
35062 enable : function(){
35063 if(inited && disabled){
35065 if(locks.length < 1){
35072 * Disable this quick tip.
35074 disable : function(){
35076 clearTimeout(showProc);
35077 clearTimeout(hideProc);
35078 clearTimeout(dismissProc);
35086 * Returns true if the quick tip is enabled, else false.
35088 isEnabled : function(){
35094 namespace : "roo", // was ext?? this may break..
35095 alt_namespace : "ext",
35096 attribute : "qtip",
35106 // backwards compat
35107 Roo.QuickTips.tips = Roo.QuickTips.register;/*
35109 * Ext JS Library 1.1.1
35110 * Copyright(c) 2006-2007, Ext JS, LLC.
35112 * Originally Released Under LGPL - original licence link has changed is not relivant.
35115 * <script type="text/javascript">
35120 * @class Roo.tree.TreePanel
35121 * @extends Roo.data.Tree
35122 * @cfg {Roo.tree.TreeNode} root The root node
35123 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
35124 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
35125 * @cfg {Boolean} enableDD true to enable drag and drop
35126 * @cfg {Boolean} enableDrag true to enable just drag
35127 * @cfg {Boolean} enableDrop true to enable just drop
35128 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
35129 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
35130 * @cfg {String} ddGroup The DD group this TreePanel belongs to
35131 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
35132 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
35133 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
35134 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
35135 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
35136 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
35137 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
35138 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
35139 * @cfg {Roo.tree.TreeLoader} loader A TreeLoader for use with this TreePanel
35140 * @cfg {Roo.tree.TreeEditor} editor The TreeEditor to display when clicked.
35141 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
35142 * @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>
35143 * @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>
35146 * @param {String/HTMLElement/Element} el The container element
35147 * @param {Object} config
35149 Roo.tree.TreePanel = function(el, config){
35151 var loader = false;
35153 root = config.root;
35154 delete config.root;
35156 if (config.loader) {
35157 loader = config.loader;
35158 delete config.loader;
35161 Roo.apply(this, config);
35162 Roo.tree.TreePanel.superclass.constructor.call(this);
35163 this.el = Roo.get(el);
35164 this.el.addClass('x-tree');
35165 //console.log(root);
35167 this.setRootNode( Roo.factory(root, Roo.tree));
35170 this.loader = Roo.factory(loader, Roo.tree);
35173 * Read-only. The id of the container element becomes this TreePanel's id.
35175 this.id = this.el.id;
35178 * @event beforeload
35179 * Fires before a node is loaded, return false to cancel
35180 * @param {Node} node The node being loaded
35182 "beforeload" : true,
35185 * Fires when a node is loaded
35186 * @param {Node} node The node that was loaded
35190 * @event textchange
35191 * Fires when the text for a node is changed
35192 * @param {Node} node The node
35193 * @param {String} text The new text
35194 * @param {String} oldText The old text
35196 "textchange" : true,
35198 * @event beforeexpand
35199 * Fires before a node is expanded, return false to cancel.
35200 * @param {Node} node The node
35201 * @param {Boolean} deep
35202 * @param {Boolean} anim
35204 "beforeexpand" : true,
35206 * @event beforecollapse
35207 * Fires before a node is collapsed, return false to cancel.
35208 * @param {Node} node The node
35209 * @param {Boolean} deep
35210 * @param {Boolean} anim
35212 "beforecollapse" : true,
35215 * Fires when a node is expanded
35216 * @param {Node} node The node
35220 * @event disabledchange
35221 * Fires when the disabled status of a node changes
35222 * @param {Node} node The node
35223 * @param {Boolean} disabled
35225 "disabledchange" : true,
35228 * Fires when a node is collapsed
35229 * @param {Node} node The node
35233 * @event beforeclick
35234 * Fires before click processing on a node. Return false to cancel the default action.
35235 * @param {Node} node The node
35236 * @param {Roo.EventObject} e The event object
35238 "beforeclick":true,
35240 * @event checkchange
35241 * Fires when a node with a checkbox's checked property changes
35242 * @param {Node} this This node
35243 * @param {Boolean} checked
35245 "checkchange":true,
35248 * Fires when a node is clicked
35249 * @param {Node} node The node
35250 * @param {Roo.EventObject} e The event object
35255 * Fires when a node is double clicked
35256 * @param {Node} node The node
35257 * @param {Roo.EventObject} e The event object
35261 * @event contextmenu
35262 * Fires when a node is right clicked
35263 * @param {Node} node The node
35264 * @param {Roo.EventObject} e The event object
35266 "contextmenu":true,
35268 * @event beforechildrenrendered
35269 * Fires right before the child nodes for a node are rendered
35270 * @param {Node} node The node
35272 "beforechildrenrendered":true,
35275 * Fires when a node starts being dragged
35276 * @param {Roo.tree.TreePanel} this
35277 * @param {Roo.tree.TreeNode} node
35278 * @param {event} e The raw browser event
35280 "startdrag" : true,
35283 * Fires when a drag operation is complete
35284 * @param {Roo.tree.TreePanel} this
35285 * @param {Roo.tree.TreeNode} node
35286 * @param {event} e The raw browser event
35291 * Fires when a dragged node is dropped on a valid DD target
35292 * @param {Roo.tree.TreePanel} this
35293 * @param {Roo.tree.TreeNode} node
35294 * @param {DD} dd The dd it was dropped on
35295 * @param {event} e The raw browser event
35299 * @event beforenodedrop
35300 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
35301 * passed to handlers has the following properties:<br />
35302 * <ul style="padding:5px;padding-left:16px;">
35303 * <li>tree - The TreePanel</li>
35304 * <li>target - The node being targeted for the drop</li>
35305 * <li>data - The drag data from the drag source</li>
35306 * <li>point - The point of the drop - append, above or below</li>
35307 * <li>source - The drag source</li>
35308 * <li>rawEvent - Raw mouse event</li>
35309 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
35310 * to be inserted by setting them on this object.</li>
35311 * <li>cancel - Set this to true to cancel the drop.</li>
35313 * @param {Object} dropEvent
35315 "beforenodedrop" : true,
35318 * Fires after a DD object is dropped on a node in this tree. The dropEvent
35319 * passed to handlers has the following properties:<br />
35320 * <ul style="padding:5px;padding-left:16px;">
35321 * <li>tree - The TreePanel</li>
35322 * <li>target - The node being targeted for the drop</li>
35323 * <li>data - The drag data from the drag source</li>
35324 * <li>point - The point of the drop - append, above or below</li>
35325 * <li>source - The drag source</li>
35326 * <li>rawEvent - Raw mouse event</li>
35327 * <li>dropNode - Dropped node(s).</li>
35329 * @param {Object} dropEvent
35333 * @event nodedragover
35334 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
35335 * passed to handlers has the following properties:<br />
35336 * <ul style="padding:5px;padding-left:16px;">
35337 * <li>tree - The TreePanel</li>
35338 * <li>target - The node being targeted for the drop</li>
35339 * <li>data - The drag data from the drag source</li>
35340 * <li>point - The point of the drop - append, above or below</li>
35341 * <li>source - The drag source</li>
35342 * <li>rawEvent - Raw mouse event</li>
35343 * <li>dropNode - Drop node(s) provided by the source.</li>
35344 * <li>cancel - Set this to true to signal drop not allowed.</li>
35346 * @param {Object} dragOverEvent
35348 "nodedragover" : true,
35350 * @event appendnode
35351 * Fires when append node to the tree
35352 * @param {Roo.tree.TreePanel} this
35353 * @param {Roo.tree.TreeNode} node
35354 * @param {Number} index The index of the newly appended node
35356 "appendnode" : true
35359 if(this.singleExpand){
35360 this.on("beforeexpand", this.restrictExpand, this);
35363 this.editor.tree = this;
35364 this.editor = Roo.factory(this.editor, Roo.tree);
35367 if (this.selModel) {
35368 this.selModel = Roo.factory(this.selModel, Roo.tree);
35372 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
35373 rootVisible : true,
35374 animate: Roo.enableFx,
35377 hlDrop : Roo.enableFx,
35381 rendererTip: false,
35383 restrictExpand : function(node){
35384 var p = node.parentNode;
35386 if(p.expandedChild && p.expandedChild.parentNode == p){
35387 p.expandedChild.collapse();
35389 p.expandedChild = node;
35393 // private override
35394 setRootNode : function(node){
35395 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
35396 if(!this.rootVisible){
35397 node.ui = new Roo.tree.RootTreeNodeUI(node);
35403 * Returns the container element for this TreePanel
35405 getEl : function(){
35410 * Returns the default TreeLoader for this TreePanel
35412 getLoader : function(){
35413 return this.loader;
35419 expandAll : function(){
35420 this.root.expand(true);
35424 * Collapse all nodes
35426 collapseAll : function(){
35427 this.root.collapse(true);
35431 * Returns the selection model used by this TreePanel
35433 getSelectionModel : function(){
35434 if(!this.selModel){
35435 this.selModel = new Roo.tree.DefaultSelectionModel();
35437 return this.selModel;
35441 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
35442 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
35443 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
35446 getChecked : function(a, startNode){
35447 startNode = startNode || this.root;
35449 var f = function(){
35450 if(this.attributes.checked){
35451 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
35454 startNode.cascade(f);
35459 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
35460 * @param {String} path
35461 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
35462 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
35463 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
35465 expandPath : function(path, attr, callback){
35466 attr = attr || "id";
35467 var keys = path.split(this.pathSeparator);
35468 var curNode = this.root;
35469 if(curNode.attributes[attr] != keys[1]){ // invalid root
35471 callback(false, null);
35476 var f = function(){
35477 if(++index == keys.length){
35479 callback(true, curNode);
35483 var c = curNode.findChild(attr, keys[index]);
35486 callback(false, curNode);
35491 c.expand(false, false, f);
35493 curNode.expand(false, false, f);
35497 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
35498 * @param {String} path
35499 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
35500 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
35501 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
35503 selectPath : function(path, attr, callback){
35504 attr = attr || "id";
35505 var keys = path.split(this.pathSeparator);
35506 var v = keys.pop();
35507 if(keys.length > 0){
35508 var f = function(success, node){
35509 if(success && node){
35510 var n = node.findChild(attr, v);
35516 }else if(callback){
35517 callback(false, n);
35521 callback(false, n);
35525 this.expandPath(keys.join(this.pathSeparator), attr, f);
35527 this.root.select();
35529 callback(true, this.root);
35534 getTreeEl : function(){
35539 * Trigger rendering of this TreePanel
35541 render : function(){
35542 if (this.innerCt) {
35543 return this; // stop it rendering more than once!!
35546 this.innerCt = this.el.createChild({tag:"ul",
35547 cls:"x-tree-root-ct " +
35548 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
35550 if(this.containerScroll){
35551 Roo.dd.ScrollManager.register(this.el);
35553 if((this.enableDD || this.enableDrop) && !this.dropZone){
35555 * The dropZone used by this tree if drop is enabled
35556 * @type Roo.tree.TreeDropZone
35558 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
35559 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
35562 if((this.enableDD || this.enableDrag) && !this.dragZone){
35564 * The dragZone used by this tree if drag is enabled
35565 * @type Roo.tree.TreeDragZone
35567 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
35568 ddGroup: this.ddGroup || "TreeDD",
35569 scroll: this.ddScroll
35572 this.getSelectionModel().init(this);
35574 Roo.log("ROOT not set in tree");
35577 this.root.render();
35578 if(!this.rootVisible){
35579 this.root.renderChildren();
35585 * Ext JS Library 1.1.1
35586 * Copyright(c) 2006-2007, Ext JS, LLC.
35588 * Originally Released Under LGPL - original licence link has changed is not relivant.
35591 * <script type="text/javascript">
35596 * @class Roo.tree.DefaultSelectionModel
35597 * @extends Roo.util.Observable
35598 * The default single selection for a TreePanel.
35599 * @param {Object} cfg Configuration
35601 Roo.tree.DefaultSelectionModel = function(cfg){
35602 this.selNode = null;
35608 * @event selectionchange
35609 * Fires when the selected node changes
35610 * @param {DefaultSelectionModel} this
35611 * @param {TreeNode} node the new selection
35613 "selectionchange" : true,
35616 * @event beforeselect
35617 * Fires before the selected node changes, return false to cancel the change
35618 * @param {DefaultSelectionModel} this
35619 * @param {TreeNode} node the new selection
35620 * @param {TreeNode} node the old selection
35622 "beforeselect" : true
35625 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
35628 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
35629 init : function(tree){
35631 tree.getTreeEl().on("keydown", this.onKeyDown, this);
35632 tree.on("click", this.onNodeClick, this);
35635 onNodeClick : function(node, e){
35636 if (e.ctrlKey && this.selNode == node) {
35637 this.unselect(node);
35645 * @param {TreeNode} node The node to select
35646 * @return {TreeNode} The selected node
35648 select : function(node){
35649 var last = this.selNode;
35650 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
35652 last.ui.onSelectedChange(false);
35654 this.selNode = node;
35655 node.ui.onSelectedChange(true);
35656 this.fireEvent("selectionchange", this, node, last);
35663 * @param {TreeNode} node The node to unselect
35665 unselect : function(node){
35666 if(this.selNode == node){
35667 this.clearSelections();
35672 * Clear all selections
35674 clearSelections : function(){
35675 var n = this.selNode;
35677 n.ui.onSelectedChange(false);
35678 this.selNode = null;
35679 this.fireEvent("selectionchange", this, null);
35685 * Get the selected node
35686 * @return {TreeNode} The selected node
35688 getSelectedNode : function(){
35689 return this.selNode;
35693 * Returns true if the node is selected
35694 * @param {TreeNode} node The node to check
35695 * @return {Boolean}
35697 isSelected : function(node){
35698 return this.selNode == node;
35702 * Selects the node above the selected node in the tree, intelligently walking the nodes
35703 * @return TreeNode The new selection
35705 selectPrevious : function(){
35706 var s = this.selNode || this.lastSelNode;
35710 var ps = s.previousSibling;
35712 if(!ps.isExpanded() || ps.childNodes.length < 1){
35713 return this.select(ps);
35715 var lc = ps.lastChild;
35716 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
35719 return this.select(lc);
35721 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
35722 return this.select(s.parentNode);
35728 * Selects the node above the selected node in the tree, intelligently walking the nodes
35729 * @return TreeNode The new selection
35731 selectNext : function(){
35732 var s = this.selNode || this.lastSelNode;
35736 if(s.firstChild && s.isExpanded()){
35737 return this.select(s.firstChild);
35738 }else if(s.nextSibling){
35739 return this.select(s.nextSibling);
35740 }else if(s.parentNode){
35742 s.parentNode.bubble(function(){
35743 if(this.nextSibling){
35744 newS = this.getOwnerTree().selModel.select(this.nextSibling);
35753 onKeyDown : function(e){
35754 var s = this.selNode || this.lastSelNode;
35755 // undesirable, but required
35760 var k = e.getKey();
35768 this.selectPrevious();
35771 e.preventDefault();
35772 if(s.hasChildNodes()){
35773 if(!s.isExpanded()){
35775 }else if(s.firstChild){
35776 this.select(s.firstChild, e);
35781 e.preventDefault();
35782 if(s.hasChildNodes() && s.isExpanded()){
35784 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
35785 this.select(s.parentNode, e);
35793 * @class Roo.tree.MultiSelectionModel
35794 * @extends Roo.util.Observable
35795 * Multi selection for a TreePanel.
35796 * @param {Object} cfg Configuration
35798 Roo.tree.MultiSelectionModel = function(){
35799 this.selNodes = [];
35803 * @event selectionchange
35804 * Fires when the selected nodes change
35805 * @param {MultiSelectionModel} this
35806 * @param {Array} nodes Array of the selected nodes
35808 "selectionchange" : true
35810 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
35814 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
35815 init : function(tree){
35817 tree.getTreeEl().on("keydown", this.onKeyDown, this);
35818 tree.on("click", this.onNodeClick, this);
35821 onNodeClick : function(node, e){
35822 this.select(node, e, e.ctrlKey);
35827 * @param {TreeNode} node The node to select
35828 * @param {EventObject} e (optional) An event associated with the selection
35829 * @param {Boolean} keepExisting True to retain existing selections
35830 * @return {TreeNode} The selected node
35832 select : function(node, e, keepExisting){
35833 if(keepExisting !== true){
35834 this.clearSelections(true);
35836 if(this.isSelected(node)){
35837 this.lastSelNode = node;
35840 this.selNodes.push(node);
35841 this.selMap[node.id] = node;
35842 this.lastSelNode = node;
35843 node.ui.onSelectedChange(true);
35844 this.fireEvent("selectionchange", this, this.selNodes);
35850 * @param {TreeNode} node The node to unselect
35852 unselect : function(node){
35853 if(this.selMap[node.id]){
35854 node.ui.onSelectedChange(false);
35855 var sn = this.selNodes;
35858 index = sn.indexOf(node);
35860 for(var i = 0, len = sn.length; i < len; i++){
35868 this.selNodes.splice(index, 1);
35870 delete this.selMap[node.id];
35871 this.fireEvent("selectionchange", this, this.selNodes);
35876 * Clear all selections
35878 clearSelections : function(suppressEvent){
35879 var sn = this.selNodes;
35881 for(var i = 0, len = sn.length; i < len; i++){
35882 sn[i].ui.onSelectedChange(false);
35884 this.selNodes = [];
35886 if(suppressEvent !== true){
35887 this.fireEvent("selectionchange", this, this.selNodes);
35893 * Returns true if the node is selected
35894 * @param {TreeNode} node The node to check
35895 * @return {Boolean}
35897 isSelected : function(node){
35898 return this.selMap[node.id] ? true : false;
35902 * Returns an array of the selected nodes
35905 getSelectedNodes : function(){
35906 return this.selNodes;
35909 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35911 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35913 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35916 * Ext JS Library 1.1.1
35917 * Copyright(c) 2006-2007, Ext JS, LLC.
35919 * Originally Released Under LGPL - original licence link has changed is not relivant.
35922 * <script type="text/javascript">
35926 * @class Roo.tree.TreeNode
35927 * @extends Roo.data.Node
35928 * @cfg {String} text The text for this node
35929 * @cfg {Boolean} expanded true to start the node expanded
35930 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35931 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35932 * @cfg {Boolean} disabled true to start the node disabled
35933 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35934 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35935 * @cfg {String} cls A css class to be added to the node
35936 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35937 * @cfg {String} href URL of the link used for the node (defaults to #)
35938 * @cfg {String} hrefTarget target frame for the link
35939 * @cfg {String} qtip An Ext QuickTip for the node
35940 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35941 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35942 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35943 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35944 * (defaults to undefined with no checkbox rendered)
35946 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35948 Roo.tree.TreeNode = function(attributes){
35949 attributes = attributes || {};
35950 if(typeof attributes == "string"){
35951 attributes = {text: attributes};
35953 this.childrenRendered = false;
35954 this.rendered = false;
35955 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35956 this.expanded = attributes.expanded === true;
35957 this.isTarget = attributes.isTarget !== false;
35958 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35959 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35962 * Read-only. The text for this node. To change it use setText().
35965 this.text = attributes.text;
35967 * True if this node is disabled.
35970 this.disabled = attributes.disabled === true;
35974 * @event textchange
35975 * Fires when the text for this node is changed
35976 * @param {Node} this This node
35977 * @param {String} text The new text
35978 * @param {String} oldText The old text
35980 "textchange" : true,
35982 * @event beforeexpand
35983 * Fires before this node is expanded, return false to cancel.
35984 * @param {Node} this This node
35985 * @param {Boolean} deep
35986 * @param {Boolean} anim
35988 "beforeexpand" : true,
35990 * @event beforecollapse
35991 * Fires before this node is collapsed, return false to cancel.
35992 * @param {Node} this This node
35993 * @param {Boolean} deep
35994 * @param {Boolean} anim
35996 "beforecollapse" : true,
35999 * Fires when this node is expanded
36000 * @param {Node} this This node
36004 * @event disabledchange
36005 * Fires when the disabled status of this node changes
36006 * @param {Node} this This node
36007 * @param {Boolean} disabled
36009 "disabledchange" : true,
36012 * Fires when this node is collapsed
36013 * @param {Node} this This node
36017 * @event beforeclick
36018 * Fires before click processing. Return false to cancel the default action.
36019 * @param {Node} this This node
36020 * @param {Roo.EventObject} e The event object
36022 "beforeclick":true,
36024 * @event checkchange
36025 * Fires when a node with a checkbox's checked property changes
36026 * @param {Node} this This node
36027 * @param {Boolean} checked
36029 "checkchange":true,
36032 * Fires when this node is clicked
36033 * @param {Node} this This node
36034 * @param {Roo.EventObject} e The event object
36039 * Fires when this node is double clicked
36040 * @param {Node} this This node
36041 * @param {Roo.EventObject} e The event object
36045 * @event contextmenu
36046 * Fires when this node is right clicked
36047 * @param {Node} this This node
36048 * @param {Roo.EventObject} e The event object
36050 "contextmenu":true,
36052 * @event beforechildrenrendered
36053 * Fires right before the child nodes for this node are rendered
36054 * @param {Node} this This node
36056 "beforechildrenrendered":true
36059 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
36062 * Read-only. The UI for this node
36065 this.ui = new uiClass(this);
36067 // finally support items[]
36068 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
36073 Roo.each(this.attributes.items, function(c) {
36074 this.appendChild(Roo.factory(c,Roo.Tree));
36076 delete this.attributes.items;
36081 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
36082 preventHScroll: true,
36084 * Returns true if this node is expanded
36085 * @return {Boolean}
36087 isExpanded : function(){
36088 return this.expanded;
36092 * Returns the UI object for this node
36093 * @return {TreeNodeUI}
36095 getUI : function(){
36099 // private override
36100 setFirstChild : function(node){
36101 var of = this.firstChild;
36102 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
36103 if(this.childrenRendered && of && node != of){
36104 of.renderIndent(true, true);
36107 this.renderIndent(true, true);
36111 // private override
36112 setLastChild : function(node){
36113 var ol = this.lastChild;
36114 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
36115 if(this.childrenRendered && ol && node != ol){
36116 ol.renderIndent(true, true);
36119 this.renderIndent(true, true);
36123 // these methods are overridden to provide lazy rendering support
36124 // private override
36125 appendChild : function()
36127 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
36128 if(node && this.childrenRendered){
36131 this.ui.updateExpandIcon();
36135 // private override
36136 removeChild : function(node){
36137 this.ownerTree.getSelectionModel().unselect(node);
36138 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
36139 // if it's been rendered remove dom node
36140 if(this.childrenRendered){
36143 if(this.childNodes.length < 1){
36144 this.collapse(false, false);
36146 this.ui.updateExpandIcon();
36148 if(!this.firstChild) {
36149 this.childrenRendered = false;
36154 // private override
36155 insertBefore : function(node, refNode){
36156 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
36157 if(newNode && refNode && this.childrenRendered){
36160 this.ui.updateExpandIcon();
36165 * Sets the text for this node
36166 * @param {String} text
36168 setText : function(text){
36169 var oldText = this.text;
36171 this.attributes.text = text;
36172 if(this.rendered){ // event without subscribing
36173 this.ui.onTextChange(this, text, oldText);
36175 this.fireEvent("textchange", this, text, oldText);
36179 * Triggers selection of this node
36181 select : function(){
36182 this.getOwnerTree().getSelectionModel().select(this);
36186 * Triggers deselection of this node
36188 unselect : function(){
36189 this.getOwnerTree().getSelectionModel().unselect(this);
36193 * Returns true if this node is selected
36194 * @return {Boolean}
36196 isSelected : function(){
36197 return this.getOwnerTree().getSelectionModel().isSelected(this);
36201 * Expand this node.
36202 * @param {Boolean} deep (optional) True to expand all children as well
36203 * @param {Boolean} anim (optional) false to cancel the default animation
36204 * @param {Function} callback (optional) A callback to be called when
36205 * expanding this node completes (does not wait for deep expand to complete).
36206 * Called with 1 parameter, this node.
36208 expand : function(deep, anim, callback){
36209 if(!this.expanded){
36210 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
36213 if(!this.childrenRendered){
36214 this.renderChildren();
36216 this.expanded = true;
36218 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
36219 this.ui.animExpand(function(){
36220 this.fireEvent("expand", this);
36221 if(typeof callback == "function"){
36225 this.expandChildNodes(true);
36227 }.createDelegate(this));
36231 this.fireEvent("expand", this);
36232 if(typeof callback == "function"){
36237 if(typeof callback == "function"){
36242 this.expandChildNodes(true);
36246 isHiddenRoot : function(){
36247 return this.isRoot && !this.getOwnerTree().rootVisible;
36251 * Collapse this node.
36252 * @param {Boolean} deep (optional) True to collapse all children as well
36253 * @param {Boolean} anim (optional) false to cancel the default animation
36255 collapse : function(deep, anim){
36256 if(this.expanded && !this.isHiddenRoot()){
36257 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
36260 this.expanded = false;
36261 if((this.getOwnerTree().animate && anim !== false) || anim){
36262 this.ui.animCollapse(function(){
36263 this.fireEvent("collapse", this);
36265 this.collapseChildNodes(true);
36267 }.createDelegate(this));
36270 this.ui.collapse();
36271 this.fireEvent("collapse", this);
36275 var cs = this.childNodes;
36276 for(var i = 0, len = cs.length; i < len; i++) {
36277 cs[i].collapse(true, false);
36283 delayedExpand : function(delay){
36284 if(!this.expandProcId){
36285 this.expandProcId = this.expand.defer(delay, this);
36290 cancelExpand : function(){
36291 if(this.expandProcId){
36292 clearTimeout(this.expandProcId);
36294 this.expandProcId = false;
36298 * Toggles expanded/collapsed state of the node
36300 toggle : function(){
36309 * Ensures all parent nodes are expanded
36311 ensureVisible : function(callback){
36312 var tree = this.getOwnerTree();
36313 tree.expandPath(this.parentNode.getPath(), false, function(){
36314 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
36315 Roo.callback(callback);
36316 }.createDelegate(this));
36320 * Expand all child nodes
36321 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
36323 expandChildNodes : function(deep){
36324 var cs = this.childNodes;
36325 for(var i = 0, len = cs.length; i < len; i++) {
36326 cs[i].expand(deep);
36331 * Collapse all child nodes
36332 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
36334 collapseChildNodes : function(deep){
36335 var cs = this.childNodes;
36336 for(var i = 0, len = cs.length; i < len; i++) {
36337 cs[i].collapse(deep);
36342 * Disables this node
36344 disable : function(){
36345 this.disabled = true;
36347 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
36348 this.ui.onDisableChange(this, true);
36350 this.fireEvent("disabledchange", this, true);
36354 * Enables this node
36356 enable : function(){
36357 this.disabled = false;
36358 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
36359 this.ui.onDisableChange(this, false);
36361 this.fireEvent("disabledchange", this, false);
36365 renderChildren : function(suppressEvent){
36366 if(suppressEvent !== false){
36367 this.fireEvent("beforechildrenrendered", this);
36369 var cs = this.childNodes;
36370 for(var i = 0, len = cs.length; i < len; i++){
36371 cs[i].render(true);
36373 this.childrenRendered = true;
36377 sort : function(fn, scope){
36378 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
36379 if(this.childrenRendered){
36380 var cs = this.childNodes;
36381 for(var i = 0, len = cs.length; i < len; i++){
36382 cs[i].render(true);
36388 render : function(bulkRender){
36389 this.ui.render(bulkRender);
36390 if(!this.rendered){
36391 this.rendered = true;
36393 this.expanded = false;
36394 this.expand(false, false);
36400 renderIndent : function(deep, refresh){
36402 this.ui.childIndent = null;
36404 this.ui.renderIndent();
36405 if(deep === true && this.childrenRendered){
36406 var cs = this.childNodes;
36407 for(var i = 0, len = cs.length; i < len; i++){
36408 cs[i].renderIndent(true, refresh);
36414 * Ext JS Library 1.1.1
36415 * Copyright(c) 2006-2007, Ext JS, LLC.
36417 * Originally Released Under LGPL - original licence link has changed is not relivant.
36420 * <script type="text/javascript">
36424 * @class Roo.tree.AsyncTreeNode
36425 * @extends Roo.tree.TreeNode
36426 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
36428 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
36430 Roo.tree.AsyncTreeNode = function(config){
36431 this.loaded = false;
36432 this.loading = false;
36433 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
36435 * @event beforeload
36436 * Fires before this node is loaded, return false to cancel
36437 * @param {Node} this This node
36439 this.addEvents({'beforeload':true, 'load': true});
36442 * Fires when this node is loaded
36443 * @param {Node} this This node
36446 * The loader used by this node (defaults to using the tree's defined loader)
36451 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
36452 expand : function(deep, anim, callback){
36453 if(this.loading){ // if an async load is already running, waiting til it's done
36455 var f = function(){
36456 if(!this.loading){ // done loading
36457 clearInterval(timer);
36458 this.expand(deep, anim, callback);
36460 }.createDelegate(this);
36461 timer = setInterval(f, 200);
36465 if(this.fireEvent("beforeload", this) === false){
36468 this.loading = true;
36469 this.ui.beforeLoad(this);
36470 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
36472 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
36476 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
36480 * Returns true if this node is currently loading
36481 * @return {Boolean}
36483 isLoading : function(){
36484 return this.loading;
36487 loadComplete : function(deep, anim, callback){
36488 this.loading = false;
36489 this.loaded = true;
36490 this.ui.afterLoad(this);
36491 this.fireEvent("load", this);
36492 this.expand(deep, anim, callback);
36496 * Returns true if this node has been loaded
36497 * @return {Boolean}
36499 isLoaded : function(){
36500 return this.loaded;
36503 hasChildNodes : function(){
36504 if(!this.isLeaf() && !this.loaded){
36507 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
36512 * Trigger a reload for this node
36513 * @param {Function} callback
36515 reload : function(callback){
36516 this.collapse(false, false);
36517 while(this.firstChild){
36518 this.removeChild(this.firstChild);
36520 this.childrenRendered = false;
36521 this.loaded = false;
36522 if(this.isHiddenRoot()){
36523 this.expanded = false;
36525 this.expand(false, false, callback);
36529 * Ext JS Library 1.1.1
36530 * Copyright(c) 2006-2007, Ext JS, LLC.
36532 * Originally Released Under LGPL - original licence link has changed is not relivant.
36535 * <script type="text/javascript">
36539 * @class Roo.tree.TreeNodeUI
36541 * @param {Object} node The node to render
36542 * The TreeNode UI implementation is separate from the
36543 * tree implementation. Unless you are customizing the tree UI,
36544 * you should never have to use this directly.
36546 Roo.tree.TreeNodeUI = function(node){
36548 this.rendered = false;
36549 this.animating = false;
36550 this.emptyIcon = Roo.BLANK_IMAGE_URL;
36553 Roo.tree.TreeNodeUI.prototype = {
36554 removeChild : function(node){
36556 this.ctNode.removeChild(node.ui.getEl());
36560 beforeLoad : function(){
36561 this.addClass("x-tree-node-loading");
36564 afterLoad : function(){
36565 this.removeClass("x-tree-node-loading");
36568 onTextChange : function(node, text, oldText){
36570 this.textNode.innerHTML = text;
36574 onDisableChange : function(node, state){
36575 this.disabled = state;
36577 this.addClass("x-tree-node-disabled");
36579 this.removeClass("x-tree-node-disabled");
36583 onSelectedChange : function(state){
36586 this.addClass("x-tree-selected");
36589 this.removeClass("x-tree-selected");
36593 onMove : function(tree, node, oldParent, newParent, index, refNode){
36594 this.childIndent = null;
36596 var targetNode = newParent.ui.getContainer();
36597 if(!targetNode){//target not rendered
36598 this.holder = document.createElement("div");
36599 this.holder.appendChild(this.wrap);
36602 var insertBefore = refNode ? refNode.ui.getEl() : null;
36604 targetNode.insertBefore(this.wrap, insertBefore);
36606 targetNode.appendChild(this.wrap);
36608 this.node.renderIndent(true);
36612 addClass : function(cls){
36614 Roo.fly(this.elNode).addClass(cls);
36618 removeClass : function(cls){
36620 Roo.fly(this.elNode).removeClass(cls);
36624 remove : function(){
36626 this.holder = document.createElement("div");
36627 this.holder.appendChild(this.wrap);
36631 fireEvent : function(){
36632 return this.node.fireEvent.apply(this.node, arguments);
36635 initEvents : function(){
36636 this.node.on("move", this.onMove, this);
36637 var E = Roo.EventManager;
36638 var a = this.anchor;
36640 var el = Roo.fly(a, '_treeui');
36642 if(Roo.isOpera){ // opera render bug ignores the CSS
36643 el.setStyle("text-decoration", "none");
36646 el.on("click", this.onClick, this);
36647 el.on("dblclick", this.onDblClick, this);
36650 Roo.EventManager.on(this.checkbox,
36651 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
36654 el.on("contextmenu", this.onContextMenu, this);
36656 var icon = Roo.fly(this.iconNode);
36657 icon.on("click", this.onClick, this);
36658 icon.on("dblclick", this.onDblClick, this);
36659 icon.on("contextmenu", this.onContextMenu, this);
36660 E.on(this.ecNode, "click", this.ecClick, this, true);
36662 if(this.node.disabled){
36663 this.addClass("x-tree-node-disabled");
36665 if(this.node.hidden){
36666 this.addClass("x-tree-node-disabled");
36668 var ot = this.node.getOwnerTree();
36669 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
36670 if(dd && (!this.node.isRoot || ot.rootVisible)){
36671 Roo.dd.Registry.register(this.elNode, {
36673 handles: this.getDDHandles(),
36679 getDDHandles : function(){
36680 return [this.iconNode, this.textNode];
36685 this.wrap.style.display = "none";
36691 this.wrap.style.display = "";
36695 onContextMenu : function(e){
36696 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
36697 e.preventDefault();
36699 this.fireEvent("contextmenu", this.node, e);
36703 onClick : function(e){
36708 if(this.fireEvent("beforeclick", this.node, e) !== false){
36709 if(!this.disabled && this.node.attributes.href){
36710 this.fireEvent("click", this.node, e);
36713 e.preventDefault();
36718 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
36719 this.node.toggle();
36722 this.fireEvent("click", this.node, e);
36728 onDblClick : function(e){
36729 e.preventDefault();
36734 this.toggleCheck();
36736 if(!this.animating && this.node.hasChildNodes()){
36737 this.node.toggle();
36739 this.fireEvent("dblclick", this.node, e);
36742 onCheckChange : function(){
36743 var checked = this.checkbox.checked;
36744 this.node.attributes.checked = checked;
36745 this.fireEvent('checkchange', this.node, checked);
36748 ecClick : function(e){
36749 if(!this.animating && this.node.hasChildNodes()){
36750 this.node.toggle();
36754 startDrop : function(){
36755 this.dropping = true;
36758 // delayed drop so the click event doesn't get fired on a drop
36759 endDrop : function(){
36760 setTimeout(function(){
36761 this.dropping = false;
36762 }.createDelegate(this), 50);
36765 expand : function(){
36766 this.updateExpandIcon();
36767 this.ctNode.style.display = "";
36770 focus : function(){
36771 if(!this.node.preventHScroll){
36772 try{this.anchor.focus();
36774 }else if(!Roo.isIE){
36776 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
36777 var l = noscroll.scrollLeft;
36778 this.anchor.focus();
36779 noscroll.scrollLeft = l;
36784 toggleCheck : function(value){
36785 var cb = this.checkbox;
36787 cb.checked = (value === undefined ? !cb.checked : value);
36793 this.anchor.blur();
36797 animExpand : function(callback){
36798 var ct = Roo.get(this.ctNode);
36800 if(!this.node.hasChildNodes()){
36801 this.updateExpandIcon();
36802 this.ctNode.style.display = "";
36803 Roo.callback(callback);
36806 this.animating = true;
36807 this.updateExpandIcon();
36810 callback : function(){
36811 this.animating = false;
36812 Roo.callback(callback);
36815 duration: this.node.ownerTree.duration || .25
36819 highlight : function(){
36820 var tree = this.node.getOwnerTree();
36821 Roo.fly(this.wrap).highlight(
36822 tree.hlColor || "C3DAF9",
36823 {endColor: tree.hlBaseColor}
36827 collapse : function(){
36828 this.updateExpandIcon();
36829 this.ctNode.style.display = "none";
36832 animCollapse : function(callback){
36833 var ct = Roo.get(this.ctNode);
36834 ct.enableDisplayMode('block');
36837 this.animating = true;
36838 this.updateExpandIcon();
36841 callback : function(){
36842 this.animating = false;
36843 Roo.callback(callback);
36846 duration: this.node.ownerTree.duration || .25
36850 getContainer : function(){
36851 return this.ctNode;
36854 getEl : function(){
36858 appendDDGhost : function(ghostNode){
36859 ghostNode.appendChild(this.elNode.cloneNode(true));
36862 getDDRepairXY : function(){
36863 return Roo.lib.Dom.getXY(this.iconNode);
36866 onRender : function(){
36870 render : function(bulkRender){
36871 var n = this.node, a = n.attributes;
36872 var targetNode = n.parentNode ?
36873 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
36875 if(!this.rendered){
36876 this.rendered = true;
36878 this.renderElements(n, a, targetNode, bulkRender);
36881 if(this.textNode.setAttributeNS){
36882 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
36884 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
36887 this.textNode.setAttribute("ext:qtip", a.qtip);
36889 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
36892 }else if(a.qtipCfg){
36893 a.qtipCfg.target = Roo.id(this.textNode);
36894 Roo.QuickTips.register(a.qtipCfg);
36897 if(!this.node.expanded){
36898 this.updateExpandIcon();
36901 if(bulkRender === true) {
36902 targetNode.appendChild(this.wrap);
36907 renderElements : function(n, a, targetNode, bulkRender)
36909 // add some indent caching, this helps performance when rendering a large tree
36910 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36911 var t = n.getOwnerTree();
36912 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36913 if (typeof(n.attributes.html) != 'undefined') {
36914 txt = n.attributes.html;
36916 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36917 var cb = typeof a.checked == 'boolean';
36918 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36919 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36920 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36921 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36922 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
36923 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
36924 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
36925 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
36926 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
36927 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36930 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36931 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36932 n.nextSibling.ui.getEl(), buf.join(""));
36934 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36937 this.elNode = this.wrap.childNodes[0];
36938 this.ctNode = this.wrap.childNodes[1];
36939 var cs = this.elNode.childNodes;
36940 this.indentNode = cs[0];
36941 this.ecNode = cs[1];
36942 this.iconNode = cs[2];
36945 this.checkbox = cs[3];
36948 this.anchor = cs[index];
36949 this.textNode = cs[index].firstChild;
36952 getAnchor : function(){
36953 return this.anchor;
36956 getTextEl : function(){
36957 return this.textNode;
36960 getIconEl : function(){
36961 return this.iconNode;
36964 isChecked : function(){
36965 return this.checkbox ? this.checkbox.checked : false;
36968 updateExpandIcon : function(){
36970 var n = this.node, c1, c2;
36971 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36972 var hasChild = n.hasChildNodes();
36976 c1 = "x-tree-node-collapsed";
36977 c2 = "x-tree-node-expanded";
36980 c1 = "x-tree-node-expanded";
36981 c2 = "x-tree-node-collapsed";
36984 this.removeClass("x-tree-node-leaf");
36985 this.wasLeaf = false;
36987 if(this.c1 != c1 || this.c2 != c2){
36988 Roo.fly(this.elNode).replaceClass(c1, c2);
36989 this.c1 = c1; this.c2 = c2;
36992 // this changes non-leafs into leafs if they have no children.
36993 // it's not very rational behaviour..
36995 if(!this.wasLeaf && this.node.leaf){
36996 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36999 this.wasLeaf = true;
37002 var ecc = "x-tree-ec-icon "+cls;
37003 if(this.ecc != ecc){
37004 this.ecNode.className = ecc;
37010 getChildIndent : function(){
37011 if(!this.childIndent){
37015 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
37017 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
37019 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
37024 this.childIndent = buf.join("");
37026 return this.childIndent;
37029 renderIndent : function(){
37032 var p = this.node.parentNode;
37034 indent = p.ui.getChildIndent();
37036 if(this.indentMarkup != indent){ // don't rerender if not required
37037 this.indentNode.innerHTML = indent;
37038 this.indentMarkup = indent;
37040 this.updateExpandIcon();
37045 Roo.tree.RootTreeNodeUI = function(){
37046 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
37048 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
37049 render : function(){
37050 if(!this.rendered){
37051 var targetNode = this.node.ownerTree.innerCt.dom;
37052 this.node.expanded = true;
37053 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
37054 this.wrap = this.ctNode = targetNode.firstChild;
37057 collapse : function(){
37059 expand : function(){
37063 * Ext JS Library 1.1.1
37064 * Copyright(c) 2006-2007, Ext JS, LLC.
37066 * Originally Released Under LGPL - original licence link has changed is not relivant.
37069 * <script type="text/javascript">
37072 * @class Roo.tree.TreeLoader
37073 * @extends Roo.util.Observable
37074 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
37075 * nodes from a specified URL. The response must be a javascript Array definition
37076 * who's elements are node definition objects. eg:
37081 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
37082 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
37089 * The old style respose with just an array is still supported, but not recommended.
37092 * A server request is sent, and child nodes are loaded only when a node is expanded.
37093 * The loading node's id is passed to the server under the parameter name "node" to
37094 * enable the server to produce the correct child nodes.
37096 * To pass extra parameters, an event handler may be attached to the "beforeload"
37097 * event, and the parameters specified in the TreeLoader's baseParams property:
37099 myTreeLoader.on("beforeload", function(treeLoader, node) {
37100 this.baseParams.category = node.attributes.category;
37105 * This would pass an HTTP parameter called "category" to the server containing
37106 * the value of the Node's "category" attribute.
37108 * Creates a new Treeloader.
37109 * @param {Object} config A config object containing config properties.
37111 Roo.tree.TreeLoader = function(config){
37112 this.baseParams = {};
37113 this.requestMethod = "POST";
37114 Roo.apply(this, config);
37119 * @event beforeload
37120 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
37121 * @param {Object} This TreeLoader object.
37122 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37123 * @param {Object} callback The callback function specified in the {@link #load} call.
37128 * Fires when the node has been successfuly loaded.
37129 * @param {Object} This TreeLoader object.
37130 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37131 * @param {Object} response The response object containing the data from the server.
37135 * @event loadexception
37136 * Fires if the network request failed.
37137 * @param {Object} This TreeLoader object.
37138 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37139 * @param {Object} response The response object containing the data from the server.
37141 loadexception : true,
37144 * Fires before a node is created, enabling you to return custom Node types
37145 * @param {Object} This TreeLoader object.
37146 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
37151 Roo.tree.TreeLoader.superclass.constructor.call(this);
37154 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
37156 * @cfg {String} dataUrl The URL from which to request a Json string which
37157 * specifies an array of node definition object representing the child nodes
37161 * @cfg {String} requestMethod either GET or POST
37162 * defaults to POST (due to BC)
37166 * @cfg {Object} baseParams (optional) An object containing properties which
37167 * specify HTTP parameters to be passed to each request for child nodes.
37170 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
37171 * created by this loader. If the attributes sent by the server have an attribute in this object,
37172 * they take priority.
37175 * @cfg {Object} uiProviders (optional) An object containing properties which
37177 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
37178 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
37179 * <i>uiProvider</i> attribute of a returned child node is a string rather
37180 * than a reference to a TreeNodeUI implementation, this that string value
37181 * is used as a property name in the uiProviders object. You can define the provider named
37182 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
37187 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
37188 * child nodes before loading.
37190 clearOnLoad : true,
37193 * @cfg {String} root (optional) Default to false. Use this to read data from an object
37194 * property on loading, rather than expecting an array. (eg. more compatible to a standard
37195 * Grid query { data : [ .....] }
37200 * @cfg {String} queryParam (optional)
37201 * Name of the query as it will be passed on the querystring (defaults to 'node')
37202 * eg. the request will be ?node=[id]
37209 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
37210 * This is called automatically when a node is expanded, but may be used to reload
37211 * a node (or append new children if the {@link #clearOnLoad} option is false.)
37212 * @param {Roo.tree.TreeNode} node
37213 * @param {Function} callback
37215 load : function(node, callback){
37216 if(this.clearOnLoad){
37217 while(node.firstChild){
37218 node.removeChild(node.firstChild);
37221 if(node.attributes.children){ // preloaded json children
37222 var cs = node.attributes.children;
37223 for(var i = 0, len = cs.length; i < len; i++){
37224 node.appendChild(this.createNode(cs[i]));
37226 if(typeof callback == "function"){
37229 }else if(this.dataUrl){
37230 this.requestData(node, callback);
37234 getParams: function(node){
37235 var buf = [], bp = this.baseParams;
37236 for(var key in bp){
37237 if(typeof bp[key] != "function"){
37238 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
37241 var n = this.queryParam === false ? 'node' : this.queryParam;
37242 buf.push(n + "=", encodeURIComponent(node.id));
37243 return buf.join("");
37246 requestData : function(node, callback){
37247 if(this.fireEvent("beforeload", this, node, callback) !== false){
37248 this.transId = Roo.Ajax.request({
37249 method:this.requestMethod,
37250 url: this.dataUrl||this.url,
37251 success: this.handleResponse,
37252 failure: this.handleFailure,
37254 argument: {callback: callback, node: node},
37255 params: this.getParams(node)
37258 // if the load is cancelled, make sure we notify
37259 // the node that we are done
37260 if(typeof callback == "function"){
37266 isLoading : function(){
37267 return this.transId ? true : false;
37270 abort : function(){
37271 if(this.isLoading()){
37272 Roo.Ajax.abort(this.transId);
37277 createNode : function(attr)
37279 // apply baseAttrs, nice idea Corey!
37280 if(this.baseAttrs){
37281 Roo.applyIf(attr, this.baseAttrs);
37283 if(this.applyLoader !== false){
37284 attr.loader = this;
37286 // uiProvider = depreciated..
37288 if(typeof(attr.uiProvider) == 'string'){
37289 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
37290 /** eval:var:attr */ eval(attr.uiProvider);
37292 if(typeof(this.uiProviders['default']) != 'undefined') {
37293 attr.uiProvider = this.uiProviders['default'];
37296 this.fireEvent('create', this, attr);
37298 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
37300 new Roo.tree.TreeNode(attr) :
37301 new Roo.tree.AsyncTreeNode(attr));
37304 processResponse : function(response, node, callback)
37306 var json = response.responseText;
37309 var o = Roo.decode(json);
37311 if (this.root === false && typeof(o.success) != undefined) {
37312 this.root = 'data'; // the default behaviour for list like data..
37315 if (this.root !== false && !o.success) {
37316 // it's a failure condition.
37317 var a = response.argument;
37318 this.fireEvent("loadexception", this, a.node, response);
37319 Roo.log("Load failed - should have a handler really");
37325 if (this.root !== false) {
37329 for(var i = 0, len = o.length; i < len; i++){
37330 var n = this.createNode(o[i]);
37332 node.appendChild(n);
37335 if(typeof callback == "function"){
37336 callback(this, node);
37339 this.handleFailure(response);
37343 handleResponse : function(response){
37344 this.transId = false;
37345 var a = response.argument;
37346 this.processResponse(response, a.node, a.callback);
37347 this.fireEvent("load", this, a.node, response);
37350 handleFailure : function(response)
37352 // should handle failure better..
37353 this.transId = false;
37354 var a = response.argument;
37355 this.fireEvent("loadexception", this, a.node, response);
37356 if(typeof a.callback == "function"){
37357 a.callback(this, a.node);
37362 * Ext JS Library 1.1.1
37363 * Copyright(c) 2006-2007, Ext JS, LLC.
37365 * Originally Released Under LGPL - original licence link has changed is not relivant.
37368 * <script type="text/javascript">
37372 * @class Roo.tree.TreeFilter
37373 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
37374 * @param {TreePanel} tree
37375 * @param {Object} config (optional)
37377 Roo.tree.TreeFilter = function(tree, config){
37379 this.filtered = {};
37380 Roo.apply(this, config);
37383 Roo.tree.TreeFilter.prototype = {
37390 * Filter the data by a specific attribute.
37391 * @param {String/RegExp} value Either string that the attribute value
37392 * should start with or a RegExp to test against the attribute
37393 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
37394 * @param {TreeNode} startNode (optional) The node to start the filter at.
37396 filter : function(value, attr, startNode){
37397 attr = attr || "text";
37399 if(typeof value == "string"){
37400 var vlen = value.length;
37401 // auto clear empty filter
37402 if(vlen == 0 && this.clearBlank){
37406 value = value.toLowerCase();
37408 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
37410 }else if(value.exec){ // regex?
37412 return value.test(n.attributes[attr]);
37415 throw 'Illegal filter type, must be string or regex';
37417 this.filterBy(f, null, startNode);
37421 * Filter by a function. The passed function will be called with each
37422 * node in the tree (or from the startNode). If the function returns true, the node is kept
37423 * otherwise it is filtered. If a node is filtered, its children are also filtered.
37424 * @param {Function} fn The filter function
37425 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
37427 filterBy : function(fn, scope, startNode){
37428 startNode = startNode || this.tree.root;
37429 if(this.autoClear){
37432 var af = this.filtered, rv = this.reverse;
37433 var f = function(n){
37434 if(n == startNode){
37440 var m = fn.call(scope || n, n);
37448 startNode.cascade(f);
37451 if(typeof id != "function"){
37453 if(n && n.parentNode){
37454 n.parentNode.removeChild(n);
37462 * Clears the current filter. Note: with the "remove" option
37463 * set a filter cannot be cleared.
37465 clear : function(){
37467 var af = this.filtered;
37469 if(typeof id != "function"){
37476 this.filtered = {};
37481 * Ext JS Library 1.1.1
37482 * Copyright(c) 2006-2007, Ext JS, LLC.
37484 * Originally Released Under LGPL - original licence link has changed is not relivant.
37487 * <script type="text/javascript">
37492 * @class Roo.tree.TreeSorter
37493 * Provides sorting of nodes in a TreePanel
37495 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
37496 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
37497 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
37498 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
37499 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
37500 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
37502 * @param {TreePanel} tree
37503 * @param {Object} config
37505 Roo.tree.TreeSorter = function(tree, config){
37506 Roo.apply(this, config);
37507 tree.on("beforechildrenrendered", this.doSort, this);
37508 tree.on("append", this.updateSort, this);
37509 tree.on("insert", this.updateSort, this);
37511 var dsc = this.dir && this.dir.toLowerCase() == "desc";
37512 var p = this.property || "text";
37513 var sortType = this.sortType;
37514 var fs = this.folderSort;
37515 var cs = this.caseSensitive === true;
37516 var leafAttr = this.leafAttr || 'leaf';
37518 this.sortFn = function(n1, n2){
37520 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
37523 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
37527 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
37528 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
37530 return dsc ? +1 : -1;
37532 return dsc ? -1 : +1;
37539 Roo.tree.TreeSorter.prototype = {
37540 doSort : function(node){
37541 node.sort(this.sortFn);
37544 compareNodes : function(n1, n2){
37545 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
37548 updateSort : function(tree, node){
37549 if(node.childrenRendered){
37550 this.doSort.defer(1, this, [node]);
37555 * Ext JS Library 1.1.1
37556 * Copyright(c) 2006-2007, Ext JS, LLC.
37558 * Originally Released Under LGPL - original licence link has changed is not relivant.
37561 * <script type="text/javascript">
37564 if(Roo.dd.DropZone){
37566 Roo.tree.TreeDropZone = function(tree, config){
37567 this.allowParentInsert = false;
37568 this.allowContainerDrop = false;
37569 this.appendOnly = false;
37570 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
37572 this.lastInsertClass = "x-tree-no-status";
37573 this.dragOverData = {};
37576 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
37577 ddGroup : "TreeDD",
37580 expandDelay : 1000,
37582 expandNode : function(node){
37583 if(node.hasChildNodes() && !node.isExpanded()){
37584 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
37588 queueExpand : function(node){
37589 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
37592 cancelExpand : function(){
37593 if(this.expandProcId){
37594 clearTimeout(this.expandProcId);
37595 this.expandProcId = false;
37599 isValidDropPoint : function(n, pt, dd, e, data){
37600 if(!n || !data){ return false; }
37601 var targetNode = n.node;
37602 var dropNode = data.node;
37603 // default drop rules
37604 if(!(targetNode && targetNode.isTarget && pt)){
37607 if(pt == "append" && targetNode.allowChildren === false){
37610 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
37613 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
37616 // reuse the object
37617 var overEvent = this.dragOverData;
37618 overEvent.tree = this.tree;
37619 overEvent.target = targetNode;
37620 overEvent.data = data;
37621 overEvent.point = pt;
37622 overEvent.source = dd;
37623 overEvent.rawEvent = e;
37624 overEvent.dropNode = dropNode;
37625 overEvent.cancel = false;
37626 var result = this.tree.fireEvent("nodedragover", overEvent);
37627 return overEvent.cancel === false && result !== false;
37630 getDropPoint : function(e, n, dd)
37634 return tn.allowChildren !== false ? "append" : false; // always append for root
37636 var dragEl = n.ddel;
37637 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
37638 var y = Roo.lib.Event.getPageY(e);
37639 //var noAppend = tn.allowChildren === false || tn.isLeaf();
37641 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
37642 var noAppend = tn.allowChildren === false;
37643 if(this.appendOnly || tn.parentNode.allowChildren === false){
37644 return noAppend ? false : "append";
37646 var noBelow = false;
37647 if(!this.allowParentInsert){
37648 noBelow = tn.hasChildNodes() && tn.isExpanded();
37650 var q = (b - t) / (noAppend ? 2 : 3);
37651 if(y >= t && y < (t + q)){
37653 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
37660 onNodeEnter : function(n, dd, e, data)
37662 this.cancelExpand();
37665 onNodeOver : function(n, dd, e, data)
37668 var pt = this.getDropPoint(e, n, dd);
37671 // auto node expand check
37672 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
37673 this.queueExpand(node);
37674 }else if(pt != "append"){
37675 this.cancelExpand();
37678 // set the insert point style on the target node
37679 var returnCls = this.dropNotAllowed;
37680 if(this.isValidDropPoint(n, pt, dd, e, data)){
37685 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
37686 cls = "x-tree-drag-insert-above";
37687 }else if(pt == "below"){
37688 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
37689 cls = "x-tree-drag-insert-below";
37691 returnCls = "x-tree-drop-ok-append";
37692 cls = "x-tree-drag-append";
37694 if(this.lastInsertClass != cls){
37695 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
37696 this.lastInsertClass = cls;
37703 onNodeOut : function(n, dd, e, data){
37705 this.cancelExpand();
37706 this.removeDropIndicators(n);
37709 onNodeDrop : function(n, dd, e, data){
37710 var point = this.getDropPoint(e, n, dd);
37711 var targetNode = n.node;
37712 targetNode.ui.startDrop();
37713 if(!this.isValidDropPoint(n, point, dd, e, data)){
37714 targetNode.ui.endDrop();
37717 // first try to find the drop node
37718 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
37721 target: targetNode,
37726 dropNode: dropNode,
37729 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
37730 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
37731 targetNode.ui.endDrop();
37734 // allow target changing
37735 targetNode = dropEvent.target;
37736 if(point == "append" && !targetNode.isExpanded()){
37737 targetNode.expand(false, null, function(){
37738 this.completeDrop(dropEvent);
37739 }.createDelegate(this));
37741 this.completeDrop(dropEvent);
37746 completeDrop : function(de){
37747 var ns = de.dropNode, p = de.point, t = de.target;
37748 if(!(ns instanceof Array)){
37752 for(var i = 0, len = ns.length; i < len; i++){
37755 t.parentNode.insertBefore(n, t);
37756 }else if(p == "below"){
37757 t.parentNode.insertBefore(n, t.nextSibling);
37763 if(this.tree.hlDrop){
37767 this.tree.fireEvent("nodedrop", de);
37770 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
37771 if(this.tree.hlDrop){
37772 dropNode.ui.focus();
37773 dropNode.ui.highlight();
37775 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
37778 getTree : function(){
37782 removeDropIndicators : function(n){
37785 Roo.fly(el).removeClass([
37786 "x-tree-drag-insert-above",
37787 "x-tree-drag-insert-below",
37788 "x-tree-drag-append"]);
37789 this.lastInsertClass = "_noclass";
37793 beforeDragDrop : function(target, e, id){
37794 this.cancelExpand();
37798 afterRepair : function(data){
37799 if(data && Roo.enableFx){
37800 data.node.ui.highlight();
37810 * Ext JS Library 1.1.1
37811 * Copyright(c) 2006-2007, Ext JS, LLC.
37813 * Originally Released Under LGPL - original licence link has changed is not relivant.
37816 * <script type="text/javascript">
37820 if(Roo.dd.DragZone){
37821 Roo.tree.TreeDragZone = function(tree, config){
37822 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
37826 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
37827 ddGroup : "TreeDD",
37829 onBeforeDrag : function(data, e){
37831 return n && n.draggable && !n.disabled;
37835 onInitDrag : function(e){
37836 var data = this.dragData;
37837 this.tree.getSelectionModel().select(data.node);
37838 this.proxy.update("");
37839 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
37840 this.tree.fireEvent("startdrag", this.tree, data.node, e);
37843 getRepairXY : function(e, data){
37844 return data.node.ui.getDDRepairXY();
37847 onEndDrag : function(data, e){
37848 this.tree.fireEvent("enddrag", this.tree, data.node, e);
37853 onValidDrop : function(dd, e, id){
37854 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
37858 beforeInvalidDrop : function(e, id){
37859 // this scrolls the original position back into view
37860 var sm = this.tree.getSelectionModel();
37861 sm.clearSelections();
37862 sm.select(this.dragData.node);
37867 * Ext JS Library 1.1.1
37868 * Copyright(c) 2006-2007, Ext JS, LLC.
37870 * Originally Released Under LGPL - original licence link has changed is not relivant.
37873 * <script type="text/javascript">
37876 * @class Roo.tree.TreeEditor
37877 * @extends Roo.Editor
37878 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
37879 * as the editor field.
37881 * @param {Object} config (used to be the tree panel.)
37882 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
37884 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
37885 * @cfg {Roo.form.TextField} field [required] The field configuration
37889 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
37892 if (oldconfig) { // old style..
37893 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
37896 tree = config.tree;
37897 config.field = config.field || {};
37898 config.field.xtype = 'TextField';
37899 field = Roo.factory(config.field, Roo.form);
37901 config = config || {};
37906 * @event beforenodeedit
37907 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37908 * false from the handler of this event.
37909 * @param {Editor} this
37910 * @param {Roo.tree.Node} node
37912 "beforenodeedit" : true
37916 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37920 tree.on('beforeclick', this.beforeNodeClick, this);
37921 tree.getTreeEl().on('mousedown', this.hide, this);
37922 this.on('complete', this.updateNode, this);
37923 this.on('beforestartedit', this.fitToTree, this);
37924 this.on('startedit', this.bindScroll, this, {delay:10});
37925 this.on('specialkey', this.onSpecialKey, this);
37928 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
37930 * @cfg {String} alignment
37931 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37937 * @cfg {Boolean} hideEl
37938 * True to hide the bound element while the editor is displayed (defaults to false)
37942 * @cfg {String} cls
37943 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37945 cls: "x-small-editor x-tree-editor",
37947 * @cfg {Boolean} shim
37948 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37954 * @cfg {Number} maxWidth
37955 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37956 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37957 * scroll and client offsets into account prior to each edit.
37964 fitToTree : function(ed, el){
37965 var td = this.tree.getTreeEl().dom, nd = el.dom;
37966 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37967 td.scrollLeft = nd.offsetLeft;
37971 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37972 this.setSize(w, '');
37974 return this.fireEvent('beforenodeedit', this, this.editNode);
37979 triggerEdit : function(node){
37980 this.completeEdit();
37981 this.editNode = node;
37982 this.startEdit(node.ui.textNode, node.text);
37986 bindScroll : function(){
37987 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37991 beforeNodeClick : function(node, e){
37992 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37993 this.lastClick = new Date();
37994 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37996 this.triggerEdit(node);
38003 updateNode : function(ed, value){
38004 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
38005 this.editNode.setText(value);
38009 onHide : function(){
38010 Roo.tree.TreeEditor.superclass.onHide.call(this);
38012 this.editNode.ui.focus();
38017 onSpecialKey : function(field, e){
38018 var k = e.getKey();
38022 }else if(k == e.ENTER && !e.hasModifier()){
38024 this.completeEdit();
38027 });//<Script type="text/javascript">
38030 * Ext JS Library 1.1.1
38031 * Copyright(c) 2006-2007, Ext JS, LLC.
38033 * Originally Released Under LGPL - original licence link has changed is not relivant.
38036 * <script type="text/javascript">
38040 * Not documented??? - probably should be...
38043 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
38044 //focus: Roo.emptyFn, // prevent odd scrolling behavior
38046 renderElements : function(n, a, targetNode, bulkRender){
38047 //consel.log("renderElements?");
38048 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
38050 var t = n.getOwnerTree();
38051 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
38053 var cols = t.columns;
38054 var bw = t.borderWidth;
38056 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
38057 var cb = typeof a.checked == "boolean";
38058 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
38059 var colcls = 'x-t-' + tid + '-c0';
38061 '<li class="x-tree-node">',
38064 '<div class="x-tree-node-el ', a.cls,'">',
38066 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
38069 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
38070 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
38071 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
38072 (a.icon ? ' x-tree-node-inline-icon' : ''),
38073 (a.iconCls ? ' '+a.iconCls : ''),
38074 '" unselectable="on" />',
38075 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
38076 (a.checked ? 'checked="checked" />' : ' />')) : ''),
38078 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
38079 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
38080 '<span unselectable="on" qtip="' + tx + '">',
38084 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
38085 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
38087 for(var i = 1, len = cols.length; i < len; i++){
38089 colcls = 'x-t-' + tid + '-c' +i;
38090 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
38091 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
38092 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
38098 '<div class="x-clear"></div></div>',
38099 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
38102 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
38103 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
38104 n.nextSibling.ui.getEl(), buf.join(""));
38106 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
38108 var el = this.wrap.firstChild;
38110 this.elNode = el.firstChild;
38111 this.ranchor = el.childNodes[1];
38112 this.ctNode = this.wrap.childNodes[1];
38113 var cs = el.firstChild.childNodes;
38114 this.indentNode = cs[0];
38115 this.ecNode = cs[1];
38116 this.iconNode = cs[2];
38119 this.checkbox = cs[3];
38122 this.anchor = cs[index];
38124 this.textNode = cs[index].firstChild;
38126 //el.on("click", this.onClick, this);
38127 //el.on("dblclick", this.onDblClick, this);
38130 // console.log(this);
38132 initEvents : function(){
38133 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
38136 var a = this.ranchor;
38138 var el = Roo.get(a);
38140 if(Roo.isOpera){ // opera render bug ignores the CSS
38141 el.setStyle("text-decoration", "none");
38144 el.on("click", this.onClick, this);
38145 el.on("dblclick", this.onDblClick, this);
38146 el.on("contextmenu", this.onContextMenu, this);
38150 /*onSelectedChange : function(state){
38153 this.addClass("x-tree-selected");
38156 this.removeClass("x-tree-selected");
38159 addClass : function(cls){
38161 Roo.fly(this.elRow).addClass(cls);
38167 removeClass : function(cls){
38169 Roo.fly(this.elRow).removeClass(cls);
38175 });//<Script type="text/javascript">
38179 * Ext JS Library 1.1.1
38180 * Copyright(c) 2006-2007, Ext JS, LLC.
38182 * Originally Released Under LGPL - original licence link has changed is not relivant.
38185 * <script type="text/javascript">
38190 * @class Roo.tree.ColumnTree
38191 * @extends Roo.tree.TreePanel
38192 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
38193 * @cfg {int} borderWidth compined right/left border allowance
38195 * @param {String/HTMLElement/Element} el The container element
38196 * @param {Object} config
38198 Roo.tree.ColumnTree = function(el, config)
38200 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
38204 * Fire this event on a container when it resizes
38205 * @param {int} w Width
38206 * @param {int} h Height
38210 this.on('resize', this.onResize, this);
38213 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
38217 borderWidth: Roo.isBorderBox ? 0 : 2,
38220 render : function(){
38221 // add the header.....
38223 Roo.tree.ColumnTree.superclass.render.apply(this);
38225 this.el.addClass('x-column-tree');
38227 this.headers = this.el.createChild(
38228 {cls:'x-tree-headers'},this.innerCt.dom);
38230 var cols = this.columns, c;
38231 var totalWidth = 0;
38233 var len = cols.length;
38234 for(var i = 0; i < len; i++){
38236 totalWidth += c.width;
38237 this.headEls.push(this.headers.createChild({
38238 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
38240 cls:'x-tree-hd-text',
38243 style:'width:'+(c.width-this.borderWidth)+'px;'
38246 this.headers.createChild({cls:'x-clear'});
38247 // prevent floats from wrapping when clipped
38248 this.headers.setWidth(totalWidth);
38249 //this.innerCt.setWidth(totalWidth);
38250 this.innerCt.setStyle({ overflow: 'auto' });
38251 this.onResize(this.width, this.height);
38255 onResize : function(w,h)
38260 this.innerCt.setWidth(this.width);
38261 this.innerCt.setHeight(this.height-20);
38264 var cols = this.columns, c;
38265 var totalWidth = 0;
38267 var len = cols.length;
38268 for(var i = 0; i < len; i++){
38270 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
38271 // it's the expander..
38272 expEl = this.headEls[i];
38275 totalWidth += c.width;
38279 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
38281 this.headers.setWidth(w-20);
38290 * Ext JS Library 1.1.1
38291 * Copyright(c) 2006-2007, Ext JS, LLC.
38293 * Originally Released Under LGPL - original licence link has changed is not relivant.
38296 * <script type="text/javascript">
38300 * @class Roo.menu.Menu
38301 * @extends Roo.util.Observable
38302 * @children Roo.menu.BaseItem
38303 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
38304 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
38306 * Creates a new Menu
38307 * @param {Object} config Configuration options
38309 Roo.menu.Menu = function(config){
38311 Roo.menu.Menu.superclass.constructor.call(this, config);
38313 this.id = this.id || Roo.id();
38316 * @event beforeshow
38317 * Fires before this menu is displayed
38318 * @param {Roo.menu.Menu} this
38322 * @event beforehide
38323 * Fires before this menu is hidden
38324 * @param {Roo.menu.Menu} this
38329 * Fires after this menu is displayed
38330 * @param {Roo.menu.Menu} this
38335 * Fires after this menu is hidden
38336 * @param {Roo.menu.Menu} this
38341 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
38342 * @param {Roo.menu.Menu} this
38343 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38344 * @param {Roo.EventObject} e
38349 * Fires when the mouse is hovering over this menu
38350 * @param {Roo.menu.Menu} this
38351 * @param {Roo.EventObject} e
38352 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38357 * Fires when the mouse exits this menu
38358 * @param {Roo.menu.Menu} this
38359 * @param {Roo.EventObject} e
38360 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38365 * Fires when a menu item contained in this menu is clicked
38366 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
38367 * @param {Roo.EventObject} e
38371 if (this.registerMenu) {
38372 Roo.menu.MenuMgr.register(this);
38375 var mis = this.items;
38376 this.items = new Roo.util.MixedCollection();
38378 this.add.apply(this, mis);
38382 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
38384 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
38388 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
38389 * for bottom-right shadow (defaults to "sides")
38393 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
38394 * this menu (defaults to "tl-tr?")
38396 subMenuAlign : "tl-tr?",
38398 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
38399 * relative to its element of origin (defaults to "tl-bl?")
38401 defaultAlign : "tl-bl?",
38403 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
38405 allowOtherMenus : false,
38407 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
38409 registerMenu : true,
38414 render : function(){
38418 var el = this.el = new Roo.Layer({
38420 shadow:this.shadow,
38422 parentEl: this.parentEl || document.body,
38426 this.keyNav = new Roo.menu.MenuNav(this);
38429 el.addClass("x-menu-plain");
38432 el.addClass(this.cls);
38434 // generic focus element
38435 this.focusEl = el.createChild({
38436 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
38438 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
38439 //disabling touch- as it's causing issues ..
38440 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
38441 ul.on('click' , this.onClick, this);
38444 ul.on("mouseover", this.onMouseOver, this);
38445 ul.on("mouseout", this.onMouseOut, this);
38446 this.items.each(function(item){
38451 var li = document.createElement("li");
38452 li.className = "x-menu-list-item";
38453 ul.dom.appendChild(li);
38454 item.render(li, this);
38461 autoWidth : function(){
38462 var el = this.el, ul = this.ul;
38466 var w = this.width;
38469 }else if(Roo.isIE){
38470 el.setWidth(this.minWidth);
38471 var t = el.dom.offsetWidth; // force recalc
38472 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
38477 delayAutoWidth : function(){
38480 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
38482 this.awTask.delay(20);
38487 findTargetItem : function(e){
38488 var t = e.getTarget(".x-menu-list-item", this.ul, true);
38489 if(t && t.menuItemId){
38490 return this.items.get(t.menuItemId);
38495 onClick : function(e){
38496 Roo.log("menu.onClick");
38497 var t = this.findTargetItem(e);
38502 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
38503 if(t == this.activeItem && t.shouldDeactivate(e)){
38504 this.activeItem.deactivate();
38505 delete this.activeItem;
38509 this.setActiveItem(t, true);
38517 this.fireEvent("click", this, t, e);
38521 setActiveItem : function(item, autoExpand){
38522 if(item != this.activeItem){
38523 if(this.activeItem){
38524 this.activeItem.deactivate();
38526 this.activeItem = item;
38527 item.activate(autoExpand);
38528 }else if(autoExpand){
38534 tryActivate : function(start, step){
38535 var items = this.items;
38536 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
38537 var item = items.get(i);
38538 if(!item.disabled && item.canActivate){
38539 this.setActiveItem(item, false);
38547 onMouseOver : function(e){
38549 if(t = this.findTargetItem(e)){
38550 if(t.canActivate && !t.disabled){
38551 this.setActiveItem(t, true);
38554 this.fireEvent("mouseover", this, e, t);
38558 onMouseOut : function(e){
38560 if(t = this.findTargetItem(e)){
38561 if(t == this.activeItem && t.shouldDeactivate(e)){
38562 this.activeItem.deactivate();
38563 delete this.activeItem;
38566 this.fireEvent("mouseout", this, e, t);
38570 * Read-only. Returns true if the menu is currently displayed, else false.
38573 isVisible : function(){
38574 return this.el && !this.hidden;
38578 * Displays this menu relative to another element
38579 * @param {String/HTMLElement/Roo.Element} element The element to align to
38580 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
38581 * the element (defaults to this.defaultAlign)
38582 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
38584 show : function(el, pos, parentMenu){
38585 this.parentMenu = parentMenu;
38589 this.fireEvent("beforeshow", this);
38590 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
38594 * Displays this menu at a specific xy position
38595 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
38596 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
38598 showAt : function(xy, parentMenu, /* private: */_e){
38599 this.parentMenu = parentMenu;
38604 this.fireEvent("beforeshow", this);
38605 xy = this.el.adjustForConstraints(xy);
38609 this.hidden = false;
38611 this.fireEvent("show", this);
38614 focus : function(){
38616 this.doFocus.defer(50, this);
38620 doFocus : function(){
38622 this.focusEl.focus();
38627 * Hides this menu and optionally all parent menus
38628 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
38630 hide : function(deep){
38631 if(this.el && this.isVisible()){
38632 this.fireEvent("beforehide", this);
38633 if(this.activeItem){
38634 this.activeItem.deactivate();
38635 this.activeItem = null;
38638 this.hidden = true;
38639 this.fireEvent("hide", this);
38641 if(deep === true && this.parentMenu){
38642 this.parentMenu.hide(true);
38647 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
38648 * Any of the following are valid:
38650 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
38651 * <li>An HTMLElement object which will be converted to a menu item</li>
38652 * <li>A menu item config object that will be created as a new menu item</li>
38653 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
38654 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
38659 var menu = new Roo.menu.Menu();
38661 // Create a menu item to add by reference
38662 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
38664 // Add a bunch of items at once using different methods.
38665 // Only the last item added will be returned.
38666 var item = menu.add(
38667 menuItem, // add existing item by ref
38668 'Dynamic Item', // new TextItem
38669 '-', // new separator
38670 { text: 'Config Item' } // new item by config
38673 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
38674 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
38677 var a = arguments, l = a.length, item;
38678 for(var i = 0; i < l; i++){
38680 if ((typeof(el) == "object") && el.xtype && el.xns) {
38681 el = Roo.factory(el, Roo.menu);
38684 if(el.render){ // some kind of Item
38685 item = this.addItem(el);
38686 }else if(typeof el == "string"){ // string
38687 if(el == "separator" || el == "-"){
38688 item = this.addSeparator();
38690 item = this.addText(el);
38692 }else if(el.tagName || el.el){ // element
38693 item = this.addElement(el);
38694 }else if(typeof el == "object"){ // must be menu item config?
38695 item = this.addMenuItem(el);
38702 * Returns this menu's underlying {@link Roo.Element} object
38703 * @return {Roo.Element} The element
38705 getEl : function(){
38713 * Adds a separator bar to the menu
38714 * @return {Roo.menu.Item} The menu item that was added
38716 addSeparator : function(){
38717 return this.addItem(new Roo.menu.Separator());
38721 * Adds an {@link Roo.Element} object to the menu
38722 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
38723 * @return {Roo.menu.Item} The menu item that was added
38725 addElement : function(el){
38726 return this.addItem(new Roo.menu.BaseItem(el));
38730 * Adds an existing object based on {@link Roo.menu.Item} to the menu
38731 * @param {Roo.menu.Item} item The menu item to add
38732 * @return {Roo.menu.Item} The menu item that was added
38734 addItem : function(item){
38735 this.items.add(item);
38737 var li = document.createElement("li");
38738 li.className = "x-menu-list-item";
38739 this.ul.dom.appendChild(li);
38740 item.render(li, this);
38741 this.delayAutoWidth();
38747 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
38748 * @param {Object} config A MenuItem config object
38749 * @return {Roo.menu.Item} The menu item that was added
38751 addMenuItem : function(config){
38752 if(!(config instanceof Roo.menu.Item)){
38753 if(typeof config.checked == "boolean"){ // must be check menu item config?
38754 config = new Roo.menu.CheckItem(config);
38756 config = new Roo.menu.Item(config);
38759 return this.addItem(config);
38763 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
38764 * @param {String} text The text to display in the menu item
38765 * @return {Roo.menu.Item} The menu item that was added
38767 addText : function(text){
38768 return this.addItem(new Roo.menu.TextItem({ text : text }));
38772 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
38773 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
38774 * @param {Roo.menu.Item} item The menu item to add
38775 * @return {Roo.menu.Item} The menu item that was added
38777 insert : function(index, item){
38778 this.items.insert(index, item);
38780 var li = document.createElement("li");
38781 li.className = "x-menu-list-item";
38782 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
38783 item.render(li, this);
38784 this.delayAutoWidth();
38790 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
38791 * @param {Roo.menu.Item} item The menu item to remove
38793 remove : function(item){
38794 this.items.removeKey(item.id);
38799 * Removes and destroys all items in the menu
38801 removeAll : function(){
38803 while(f = this.items.first()){
38809 // MenuNav is a private utility class used internally by the Menu
38810 Roo.menu.MenuNav = function(menu){
38811 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
38812 this.scope = this.menu = menu;
38815 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
38816 doRelay : function(e, h){
38817 var k = e.getKey();
38818 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
38819 this.menu.tryActivate(0, 1);
38822 return h.call(this.scope || this, e, this.menu);
38825 up : function(e, m){
38826 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
38827 m.tryActivate(m.items.length-1, -1);
38831 down : function(e, m){
38832 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
38833 m.tryActivate(0, 1);
38837 right : function(e, m){
38839 m.activeItem.expandMenu(true);
38843 left : function(e, m){
38845 if(m.parentMenu && m.parentMenu.activeItem){
38846 m.parentMenu.activeItem.activate();
38850 enter : function(e, m){
38852 e.stopPropagation();
38853 m.activeItem.onClick(e);
38854 m.fireEvent("click", this, m.activeItem);
38860 * Ext JS Library 1.1.1
38861 * Copyright(c) 2006-2007, Ext JS, LLC.
38863 * Originally Released Under LGPL - original licence link has changed is not relivant.
38866 * <script type="text/javascript">
38870 * @class Roo.menu.MenuMgr
38871 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
38874 Roo.menu.MenuMgr = function(){
38875 var menus, active, groups = {}, attached = false, lastShow = new Date();
38877 // private - called when first menu is created
38880 active = new Roo.util.MixedCollection();
38881 Roo.get(document).addKeyListener(27, function(){
38882 if(active.length > 0){
38889 function hideAll(){
38890 if(active && active.length > 0){
38891 var c = active.clone();
38892 c.each(function(m){
38899 function onHide(m){
38901 if(active.length < 1){
38902 Roo.get(document).un("mousedown", onMouseDown);
38908 function onShow(m){
38909 var last = active.last();
38910 lastShow = new Date();
38913 Roo.get(document).on("mousedown", onMouseDown);
38917 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38918 m.parentMenu.activeChild = m;
38919 }else if(last && last.isVisible()){
38920 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
38925 function onBeforeHide(m){
38927 m.activeChild.hide();
38929 if(m.autoHideTimer){
38930 clearTimeout(m.autoHideTimer);
38931 delete m.autoHideTimer;
38936 function onBeforeShow(m){
38937 var pm = m.parentMenu;
38938 if(!pm && !m.allowOtherMenus){
38940 }else if(pm && pm.activeChild && active != m){
38941 pm.activeChild.hide();
38946 function onMouseDown(e){
38947 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38953 function onBeforeCheck(mi, state){
38955 var g = groups[mi.group];
38956 for(var i = 0, l = g.length; i < l; i++){
38958 g[i].setChecked(false);
38967 * Hides all menus that are currently visible
38969 hideAll : function(){
38974 register : function(menu){
38978 menus[menu.id] = menu;
38979 menu.on("beforehide", onBeforeHide);
38980 menu.on("hide", onHide);
38981 menu.on("beforeshow", onBeforeShow);
38982 menu.on("show", onShow);
38983 var g = menu.group;
38984 if(g && menu.events["checkchange"]){
38988 groups[g].push(menu);
38989 menu.on("checkchange", onCheck);
38994 * Returns a {@link Roo.menu.Menu} object
38995 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38996 * be used to generate and return a new Menu instance.
38998 get : function(menu){
38999 if(typeof menu == "string"){ // menu id
39000 return menus[menu];
39001 }else if(menu.events){ // menu instance
39003 }else if(typeof menu.length == 'number'){ // array of menu items?
39004 return new Roo.menu.Menu({items:menu});
39005 }else{ // otherwise, must be a config
39006 return new Roo.menu.Menu(menu);
39011 unregister : function(menu){
39012 delete menus[menu.id];
39013 menu.un("beforehide", onBeforeHide);
39014 menu.un("hide", onHide);
39015 menu.un("beforeshow", onBeforeShow);
39016 menu.un("show", onShow);
39017 var g = menu.group;
39018 if(g && menu.events["checkchange"]){
39019 groups[g].remove(menu);
39020 menu.un("checkchange", onCheck);
39025 registerCheckable : function(menuItem){
39026 var g = menuItem.group;
39031 groups[g].push(menuItem);
39032 menuItem.on("beforecheckchange", onBeforeCheck);
39037 unregisterCheckable : function(menuItem){
39038 var g = menuItem.group;
39040 groups[g].remove(menuItem);
39041 menuItem.un("beforecheckchange", onBeforeCheck);
39047 * Ext JS Library 1.1.1
39048 * Copyright(c) 2006-2007, Ext JS, LLC.
39050 * Originally Released Under LGPL - original licence link has changed is not relivant.
39053 * <script type="text/javascript">
39058 * @class Roo.menu.BaseItem
39059 * @extends Roo.Component
39061 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
39062 * management and base configuration options shared by all menu components.
39064 * Creates a new BaseItem
39065 * @param {Object} config Configuration options
39067 Roo.menu.BaseItem = function(config){
39068 Roo.menu.BaseItem.superclass.constructor.call(this, config);
39073 * Fires when this item is clicked
39074 * @param {Roo.menu.BaseItem} this
39075 * @param {Roo.EventObject} e
39080 * Fires when this item is activated
39081 * @param {Roo.menu.BaseItem} this
39085 * @event deactivate
39086 * Fires when this item is deactivated
39087 * @param {Roo.menu.BaseItem} this
39093 this.on("click", this.handler, this.scope, true);
39097 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
39099 * @cfg {Function} handler
39100 * A function that will handle the click event of this menu item (defaults to undefined)
39103 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
39105 canActivate : false,
39108 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
39113 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
39115 activeClass : "x-menu-item-active",
39117 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
39119 hideOnClick : true,
39121 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
39126 ctype: "Roo.menu.BaseItem",
39129 actionMode : "container",
39132 render : function(container, parentMenu){
39133 this.parentMenu = parentMenu;
39134 Roo.menu.BaseItem.superclass.render.call(this, container);
39135 this.container.menuItemId = this.id;
39139 onRender : function(container, position){
39140 this.el = Roo.get(this.el);
39141 container.dom.appendChild(this.el.dom);
39145 onClick : function(e){
39146 if(!this.disabled && this.fireEvent("click", this, e) !== false
39147 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
39148 this.handleClick(e);
39155 activate : function(){
39159 var li = this.container;
39160 li.addClass(this.activeClass);
39161 this.region = li.getRegion().adjust(2, 2, -2, -2);
39162 this.fireEvent("activate", this);
39167 deactivate : function(){
39168 this.container.removeClass(this.activeClass);
39169 this.fireEvent("deactivate", this);
39173 shouldDeactivate : function(e){
39174 return !this.region || !this.region.contains(e.getPoint());
39178 handleClick : function(e){
39179 if(this.hideOnClick){
39180 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
39185 expandMenu : function(autoActivate){
39190 hideMenu : function(){
39195 * Ext JS Library 1.1.1
39196 * Copyright(c) 2006-2007, Ext JS, LLC.
39198 * Originally Released Under LGPL - original licence link has changed is not relivant.
39201 * <script type="text/javascript">
39205 * @class Roo.menu.Adapter
39206 * @extends Roo.menu.BaseItem
39208 * 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.
39209 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
39211 * Creates a new Adapter
39212 * @param {Object} config Configuration options
39214 Roo.menu.Adapter = function(component, config){
39215 Roo.menu.Adapter.superclass.constructor.call(this, config);
39216 this.component = component;
39218 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
39220 canActivate : true,
39223 onRender : function(container, position){
39224 this.component.render(container);
39225 this.el = this.component.getEl();
39229 activate : function(){
39233 this.component.focus();
39234 this.fireEvent("activate", this);
39239 deactivate : function(){
39240 this.fireEvent("deactivate", this);
39244 disable : function(){
39245 this.component.disable();
39246 Roo.menu.Adapter.superclass.disable.call(this);
39250 enable : function(){
39251 this.component.enable();
39252 Roo.menu.Adapter.superclass.enable.call(this);
39256 * Ext JS Library 1.1.1
39257 * Copyright(c) 2006-2007, Ext JS, LLC.
39259 * Originally Released Under LGPL - original licence link has changed is not relivant.
39262 * <script type="text/javascript">
39266 * @class Roo.menu.TextItem
39267 * @extends Roo.menu.BaseItem
39268 * Adds a static text string to a menu, usually used as either a heading or group separator.
39269 * Note: old style constructor with text is still supported.
39272 * Creates a new TextItem
39273 * @param {Object} cfg Configuration
39275 Roo.menu.TextItem = function(cfg){
39276 if (typeof(cfg) == 'string') {
39279 Roo.apply(this,cfg);
39282 Roo.menu.TextItem.superclass.constructor.call(this);
39285 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
39287 * @cfg {String} text Text to show on item.
39292 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
39294 hideOnClick : false,
39296 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
39298 itemCls : "x-menu-text",
39301 onRender : function(){
39302 var s = document.createElement("span");
39303 s.className = this.itemCls;
39304 s.innerHTML = this.text;
39306 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
39310 * Ext JS Library 1.1.1
39311 * Copyright(c) 2006-2007, Ext JS, LLC.
39313 * Originally Released Under LGPL - original licence link has changed is not relivant.
39316 * <script type="text/javascript">
39320 * @class Roo.menu.Separator
39321 * @extends Roo.menu.BaseItem
39322 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
39323 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
39325 * @param {Object} config Configuration options
39327 Roo.menu.Separator = function(config){
39328 Roo.menu.Separator.superclass.constructor.call(this, config);
39331 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
39333 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
39335 itemCls : "x-menu-sep",
39337 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
39339 hideOnClick : false,
39342 onRender : function(li){
39343 var s = document.createElement("span");
39344 s.className = this.itemCls;
39345 s.innerHTML = " ";
39347 li.addClass("x-menu-sep-li");
39348 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
39352 * Ext JS Library 1.1.1
39353 * Copyright(c) 2006-2007, Ext JS, LLC.
39355 * Originally Released Under LGPL - original licence link has changed is not relivant.
39358 * <script type="text/javascript">
39361 * @class Roo.menu.Item
39362 * @extends Roo.menu.BaseItem
39363 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
39364 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
39365 * activation and click handling.
39367 * Creates a new Item
39368 * @param {Object} config Configuration options
39370 Roo.menu.Item = function(config){
39371 Roo.menu.Item.superclass.constructor.call(this, config);
39373 this.menu = Roo.menu.MenuMgr.get(this.menu);
39376 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
39378 * @cfg {Roo.menu.Menu} menu
39382 * @cfg {String} text
39383 * The text to show on the menu item.
39387 * @cfg {String} HTML to render in menu
39388 * The text to show on the menu item (HTML version).
39392 * @cfg {String} icon
39393 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
39397 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
39399 itemCls : "x-menu-item",
39401 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
39403 canActivate : true,
39405 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
39408 // doc'd in BaseItem
39412 ctype: "Roo.menu.Item",
39415 onRender : function(container, position){
39416 var el = document.createElement("a");
39417 el.hideFocus = true;
39418 el.unselectable = "on";
39419 el.href = this.href || "#";
39420 if(this.hrefTarget){
39421 el.target = this.hrefTarget;
39423 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
39425 var html = this.html.length ? this.html : String.format('{0}',this.text);
39427 el.innerHTML = String.format(
39428 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
39429 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
39431 Roo.menu.Item.superclass.onRender.call(this, container, position);
39435 * Sets the text to display in this menu item
39436 * @param {String} text The text to display
39437 * @param {Boolean} isHTML true to indicate text is pure html.
39439 setText : function(text, isHTML){
39447 var html = this.html.length ? this.html : String.format('{0}',this.text);
39449 this.el.update(String.format(
39450 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
39451 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
39452 this.parentMenu.autoWidth();
39457 handleClick : function(e){
39458 if(!this.href){ // if no link defined, stop the event automatically
39461 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
39465 activate : function(autoExpand){
39466 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
39476 shouldDeactivate : function(e){
39477 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
39478 if(this.menu && this.menu.isVisible()){
39479 return !this.menu.getEl().getRegion().contains(e.getPoint());
39487 deactivate : function(){
39488 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
39493 expandMenu : function(autoActivate){
39494 if(!this.disabled && this.menu){
39495 clearTimeout(this.hideTimer);
39496 delete this.hideTimer;
39497 if(!this.menu.isVisible() && !this.showTimer){
39498 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
39499 }else if (this.menu.isVisible() && autoActivate){
39500 this.menu.tryActivate(0, 1);
39506 deferExpand : function(autoActivate){
39507 delete this.showTimer;
39508 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
39510 this.menu.tryActivate(0, 1);
39515 hideMenu : function(){
39516 clearTimeout(this.showTimer);
39517 delete this.showTimer;
39518 if(!this.hideTimer && this.menu && this.menu.isVisible()){
39519 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
39524 deferHide : function(){
39525 delete this.hideTimer;
39530 * Ext JS Library 1.1.1
39531 * Copyright(c) 2006-2007, Ext JS, LLC.
39533 * Originally Released Under LGPL - original licence link has changed is not relivant.
39536 * <script type="text/javascript">
39540 * @class Roo.menu.CheckItem
39541 * @extends Roo.menu.Item
39542 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
39544 * Creates a new CheckItem
39545 * @param {Object} config Configuration options
39547 Roo.menu.CheckItem = function(config){
39548 Roo.menu.CheckItem.superclass.constructor.call(this, config);
39551 * @event beforecheckchange
39552 * Fires before the checked value is set, providing an opportunity to cancel if needed
39553 * @param {Roo.menu.CheckItem} this
39554 * @param {Boolean} checked The new checked value that will be set
39556 "beforecheckchange" : true,
39558 * @event checkchange
39559 * Fires after the checked value has been set
39560 * @param {Roo.menu.CheckItem} this
39561 * @param {Boolean} checked The checked value that was set
39563 "checkchange" : true
39565 if(this.checkHandler){
39566 this.on('checkchange', this.checkHandler, this.scope);
39569 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
39571 * @cfg {String} group
39572 * All check items with the same group name will automatically be grouped into a single-select
39573 * radio button group (defaults to '')
39576 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
39578 itemCls : "x-menu-item x-menu-check-item",
39580 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
39582 groupClass : "x-menu-group-item",
39585 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
39586 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
39587 * initialized with checked = true will be rendered as checked.
39592 ctype: "Roo.menu.CheckItem",
39595 onRender : function(c){
39596 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
39598 this.el.addClass(this.groupClass);
39600 Roo.menu.MenuMgr.registerCheckable(this);
39602 this.checked = false;
39603 this.setChecked(true, true);
39608 destroy : function(){
39610 Roo.menu.MenuMgr.unregisterCheckable(this);
39612 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
39616 * Set the checked state of this item
39617 * @param {Boolean} checked The new checked value
39618 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
39620 setChecked : function(state, suppressEvent){
39621 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
39622 if(this.container){
39623 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
39625 this.checked = state;
39626 if(suppressEvent !== true){
39627 this.fireEvent("checkchange", this, state);
39633 handleClick : function(e){
39634 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
39635 this.setChecked(!this.checked);
39637 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
39641 * Ext JS Library 1.1.1
39642 * Copyright(c) 2006-2007, Ext JS, LLC.
39644 * Originally Released Under LGPL - original licence link has changed is not relivant.
39647 * <script type="text/javascript">
39651 * @class Roo.menu.DateItem
39652 * @extends Roo.menu.Adapter
39653 * A menu item that wraps the {@link Roo.DatPicker} component.
39655 * Creates a new DateItem
39656 * @param {Object} config Configuration options
39658 Roo.menu.DateItem = function(config){
39659 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
39660 /** The Roo.DatePicker object @type Roo.DatePicker */
39661 this.picker = this.component;
39662 this.addEvents({select: true});
39664 this.picker.on("render", function(picker){
39665 picker.getEl().swallowEvent("click");
39666 picker.container.addClass("x-menu-date-item");
39669 this.picker.on("select", this.onSelect, this);
39672 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
39674 onSelect : function(picker, date){
39675 this.fireEvent("select", this, date, picker);
39676 Roo.menu.DateItem.superclass.handleClick.call(this);
39680 * Ext JS Library 1.1.1
39681 * Copyright(c) 2006-2007, Ext JS, LLC.
39683 * Originally Released Under LGPL - original licence link has changed is not relivant.
39686 * <script type="text/javascript">
39690 * @class Roo.menu.ColorItem
39691 * @extends Roo.menu.Adapter
39692 * A menu item that wraps the {@link Roo.ColorPalette} component.
39694 * Creates a new ColorItem
39695 * @param {Object} config Configuration options
39697 Roo.menu.ColorItem = function(config){
39698 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
39699 /** The Roo.ColorPalette object @type Roo.ColorPalette */
39700 this.palette = this.component;
39701 this.relayEvents(this.palette, ["select"]);
39702 if(this.selectHandler){
39703 this.on('select', this.selectHandler, this.scope);
39706 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
39708 * Ext JS Library 1.1.1
39709 * Copyright(c) 2006-2007, Ext JS, LLC.
39711 * Originally Released Under LGPL - original licence link has changed is not relivant.
39714 * <script type="text/javascript">
39719 * @class Roo.menu.DateMenu
39720 * @extends Roo.menu.Menu
39721 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
39723 * Creates a new DateMenu
39724 * @param {Object} config Configuration options
39726 Roo.menu.DateMenu = function(config){
39727 Roo.menu.DateMenu.superclass.constructor.call(this, config);
39729 var di = new Roo.menu.DateItem(config);
39732 * The {@link Roo.DatePicker} instance for this DateMenu
39735 this.picker = di.picker;
39738 * @param {DatePicker} picker
39739 * @param {Date} date
39741 this.relayEvents(di, ["select"]);
39742 this.on('beforeshow', function(){
39744 this.picker.hideMonthPicker(false);
39748 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
39752 * Ext JS Library 1.1.1
39753 * Copyright(c) 2006-2007, Ext JS, LLC.
39755 * Originally Released Under LGPL - original licence link has changed is not relivant.
39758 * <script type="text/javascript">
39763 * @class Roo.menu.ColorMenu
39764 * @extends Roo.menu.Menu
39765 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
39767 * Creates a new ColorMenu
39768 * @param {Object} config Configuration options
39770 Roo.menu.ColorMenu = function(config){
39771 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
39773 var ci = new Roo.menu.ColorItem(config);
39776 * The {@link Roo.ColorPalette} instance for this ColorMenu
39777 * @type ColorPalette
39779 this.palette = ci.palette;
39782 * @param {ColorPalette} palette
39783 * @param {String} color
39785 this.relayEvents(ci, ["select"]);
39787 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
39789 * Ext JS Library 1.1.1
39790 * Copyright(c) 2006-2007, Ext JS, LLC.
39792 * Originally Released Under LGPL - original licence link has changed is not relivant.
39795 * <script type="text/javascript">
39799 * @class Roo.form.TextItem
39800 * @extends Roo.BoxComponent
39801 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39803 * Creates a new TextItem
39804 * @param {Object} config Configuration options
39806 Roo.form.TextItem = function(config){
39807 Roo.form.TextItem.superclass.constructor.call(this, config);
39810 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
39813 * @cfg {String} tag the tag for this item (default div)
39817 * @cfg {String} html the content for this item
39821 getAutoCreate : function()
39834 onRender : function(ct, position)
39836 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
39839 var cfg = this.getAutoCreate();
39841 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39843 if (!cfg.name.length) {
39846 this.el = ct.createChild(cfg, position);
39851 * @param {String} html update the Contents of the element.
39853 setHTML : function(html)
39855 this.fieldEl.dom.innerHTML = html;
39860 * Ext JS Library 1.1.1
39861 * Copyright(c) 2006-2007, Ext JS, LLC.
39863 * Originally Released Under LGPL - original licence link has changed is not relivant.
39866 * <script type="text/javascript">
39870 * @class Roo.form.Field
39871 * @extends Roo.BoxComponent
39872 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39874 * Creates a new Field
39875 * @param {Object} config Configuration options
39877 Roo.form.Field = function(config){
39878 Roo.form.Field.superclass.constructor.call(this, config);
39881 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
39883 * @cfg {String} fieldLabel Label to use when rendering a form.
39886 * @cfg {String} qtip Mouse over tip
39890 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
39892 invalidClass : "x-form-invalid",
39894 * @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")
39896 invalidText : "The value in this field is invalid",
39898 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
39900 focusClass : "x-form-focus",
39902 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
39903 automatic validation (defaults to "keyup").
39905 validationEvent : "keyup",
39907 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
39909 validateOnBlur : true,
39911 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39913 validationDelay : 250,
39915 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39916 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39918 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39920 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39922 fieldClass : "x-form-field",
39924 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
39927 ----------- ----------------------------------------------------------------------
39928 qtip Display a quick tip when the user hovers over the field
39929 title Display a default browser title attribute popup
39930 under Add a block div beneath the field containing the error text
39931 side Add an error icon to the right of the field with a popup on hover
39932 [element id] Add the error text directly to the innerHTML of the specified element
39935 msgTarget : 'qtip',
39937 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39942 * @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.
39947 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39952 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39954 inputType : undefined,
39957 * @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).
39959 tabIndex : undefined,
39962 isFormField : true,
39967 * @property {Roo.Element} fieldEl
39968 * Element Containing the rendered Field (with label etc.)
39971 * @cfg {Mixed} value A value to initialize this field with.
39976 * @cfg {String} name The field's HTML name attribute.
39979 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39982 loadedValue : false,
39986 initComponent : function(){
39987 Roo.form.Field.superclass.initComponent.call(this);
39991 * Fires when this field receives input focus.
39992 * @param {Roo.form.Field} this
39997 * Fires when this field loses input focus.
39998 * @param {Roo.form.Field} this
40002 * @event specialkey
40003 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
40004 * {@link Roo.EventObject#getKey} to determine which key was pressed.
40005 * @param {Roo.form.Field} this
40006 * @param {Roo.EventObject} e The event object
40011 * Fires just before the field blurs if the field value has changed.
40012 * @param {Roo.form.Field} this
40013 * @param {Mixed} newValue The new value
40014 * @param {Mixed} oldValue The original value
40019 * Fires after the field has been marked as invalid.
40020 * @param {Roo.form.Field} this
40021 * @param {String} msg The validation message
40026 * Fires after the field has been validated with no errors.
40027 * @param {Roo.form.Field} this
40032 * Fires after the key up
40033 * @param {Roo.form.Field} this
40034 * @param {Roo.EventObject} e The event Object
40041 * Returns the name attribute of the field if available
40042 * @return {String} name The field name
40044 getName: function(){
40045 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40049 onRender : function(ct, position){
40050 Roo.form.Field.superclass.onRender.call(this, ct, position);
40052 var cfg = this.getAutoCreate();
40054 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
40056 if (!cfg.name.length) {
40059 if(this.inputType){
40060 cfg.type = this.inputType;
40062 this.el = ct.createChild(cfg, position);
40064 var type = this.el.dom.type;
40066 if(type == 'password'){
40069 this.el.addClass('x-form-'+type);
40072 this.el.dom.readOnly = true;
40074 if(this.tabIndex !== undefined){
40075 this.el.dom.setAttribute('tabIndex', this.tabIndex);
40078 this.el.addClass([this.fieldClass, this.cls]);
40083 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
40084 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
40085 * @return {Roo.form.Field} this
40087 applyTo : function(target){
40088 this.allowDomMove = false;
40089 this.el = Roo.get(target);
40090 this.render(this.el.dom.parentNode);
40095 initValue : function(){
40096 if(this.value !== undefined){
40097 this.setValue(this.value);
40098 }else if(this.el.dom.value.length > 0){
40099 this.setValue(this.el.dom.value);
40104 * Returns true if this field has been changed since it was originally loaded and is not disabled.
40105 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
40107 isDirty : function() {
40108 if(this.disabled) {
40111 return String(this.getValue()) !== String(this.originalValue);
40115 * stores the current value in loadedValue
40117 resetHasChanged : function()
40119 this.loadedValue = String(this.getValue());
40122 * checks the current value against the 'loaded' value.
40123 * Note - will return false if 'resetHasChanged' has not been called first.
40125 hasChanged : function()
40127 if(this.disabled || this.readOnly) {
40130 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
40136 afterRender : function(){
40137 Roo.form.Field.superclass.afterRender.call(this);
40142 fireKey : function(e){
40143 //Roo.log('field ' + e.getKey());
40144 if(e.isNavKeyPress()){
40145 this.fireEvent("specialkey", this, e);
40150 * Resets the current field value to the originally loaded value and clears any validation messages
40152 reset : function(){
40153 this.setValue(this.resetValue);
40154 this.originalValue = this.getValue();
40155 this.clearInvalid();
40159 initEvents : function(){
40160 // safari killled keypress - so keydown is now used..
40161 this.el.on("keydown" , this.fireKey, this);
40162 this.el.on("focus", this.onFocus, this);
40163 this.el.on("blur", this.onBlur, this);
40164 this.el.relayEvent('keyup', this);
40166 // reference to original value for reset
40167 this.originalValue = this.getValue();
40168 this.resetValue = this.getValue();
40172 onFocus : function(){
40173 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40174 this.el.addClass(this.focusClass);
40176 if(!this.hasFocus){
40177 this.hasFocus = true;
40178 this.startValue = this.getValue();
40179 this.fireEvent("focus", this);
40183 beforeBlur : Roo.emptyFn,
40186 onBlur : function(){
40188 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40189 this.el.removeClass(this.focusClass);
40191 this.hasFocus = false;
40192 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40195 var v = this.getValue();
40196 if(String(v) !== String(this.startValue)){
40197 this.fireEvent('change', this, v, this.startValue);
40199 this.fireEvent("blur", this);
40203 * Returns whether or not the field value is currently valid
40204 * @param {Boolean} preventMark True to disable marking the field invalid
40205 * @return {Boolean} True if the value is valid, else false
40207 isValid : function(preventMark){
40211 var restore = this.preventMark;
40212 this.preventMark = preventMark === true;
40213 var v = this.validateValue(this.processValue(this.getRawValue()));
40214 this.preventMark = restore;
40219 * Validates the field value
40220 * @return {Boolean} True if the value is valid, else false
40222 validate : function(){
40223 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
40224 this.clearInvalid();
40230 processValue : function(value){
40235 // Subclasses should provide the validation implementation by overriding this
40236 validateValue : function(value){
40241 * Mark this field as invalid
40242 * @param {String} msg The validation message
40244 markInvalid : function(msg){
40245 if(!this.rendered || this.preventMark){ // not rendered
40249 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
40251 obj.el.addClass(this.invalidClass);
40252 msg = msg || this.invalidText;
40253 switch(this.msgTarget){
40255 obj.el.dom.qtip = msg;
40256 obj.el.dom.qclass = 'x-form-invalid-tip';
40257 if(Roo.QuickTips){ // fix for floating editors interacting with DND
40258 Roo.QuickTips.enable();
40262 this.el.dom.title = msg;
40266 var elp = this.el.findParent('.x-form-element', 5, true);
40267 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
40268 this.errorEl.setWidth(elp.getWidth(true)-20);
40270 this.errorEl.update(msg);
40271 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
40274 if(!this.errorIcon){
40275 var elp = this.el.findParent('.x-form-element', 5, true);
40276 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
40278 this.alignErrorIcon();
40279 this.errorIcon.dom.qtip = msg;
40280 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
40281 this.errorIcon.show();
40282 this.on('resize', this.alignErrorIcon, this);
40285 var t = Roo.getDom(this.msgTarget);
40287 t.style.display = this.msgDisplay;
40290 this.fireEvent('invalid', this, msg);
40294 alignErrorIcon : function(){
40295 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
40299 * Clear any invalid styles/messages for this field
40301 clearInvalid : function(){
40302 if(!this.rendered || this.preventMark){ // not rendered
40305 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
40307 obj.el.removeClass(this.invalidClass);
40308 switch(this.msgTarget){
40310 obj.el.dom.qtip = '';
40313 this.el.dom.title = '';
40317 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
40321 if(this.errorIcon){
40322 this.errorIcon.dom.qtip = '';
40323 this.errorIcon.hide();
40324 this.un('resize', this.alignErrorIcon, this);
40328 var t = Roo.getDom(this.msgTarget);
40330 t.style.display = 'none';
40333 this.fireEvent('valid', this);
40337 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
40338 * @return {Mixed} value The field value
40340 getRawValue : function(){
40341 var v = this.el.getValue();
40347 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
40348 * @return {Mixed} value The field value
40350 getValue : function(){
40351 var v = this.el.getValue();
40357 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
40358 * @param {Mixed} value The value to set
40360 setRawValue : function(v){
40361 return this.el.dom.value = (v === null || v === undefined ? '' : v);
40365 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
40366 * @param {Mixed} value The value to set
40368 setValue : function(v){
40371 this.el.dom.value = (v === null || v === undefined ? '' : v);
40376 adjustSize : function(w, h){
40377 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
40378 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
40382 adjustWidth : function(tag, w){
40383 tag = tag.toLowerCase();
40384 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
40385 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
40386 if(tag == 'input'){
40389 if(tag == 'textarea'){
40392 }else if(Roo.isOpera){
40393 if(tag == 'input'){
40396 if(tag == 'textarea'){
40406 // anything other than normal should be considered experimental
40407 Roo.form.Field.msgFx = {
40409 show: function(msgEl, f){
40410 msgEl.setDisplayed('block');
40413 hide : function(msgEl, f){
40414 msgEl.setDisplayed(false).update('');
40419 show: function(msgEl, f){
40420 msgEl.slideIn('t', {stopFx:true});
40423 hide : function(msgEl, f){
40424 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
40429 show: function(msgEl, f){
40430 msgEl.fixDisplay();
40431 msgEl.alignTo(f.el, 'tl-tr');
40432 msgEl.slideIn('l', {stopFx:true});
40435 hide : function(msgEl, f){
40436 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
40441 * Ext JS Library 1.1.1
40442 * Copyright(c) 2006-2007, Ext JS, LLC.
40444 * Originally Released Under LGPL - original licence link has changed is not relivant.
40447 * <script type="text/javascript">
40452 * @class Roo.form.TextField
40453 * @extends Roo.form.Field
40454 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
40455 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
40457 * Creates a new TextField
40458 * @param {Object} config Configuration options
40460 Roo.form.TextField = function(config){
40461 Roo.form.TextField.superclass.constructor.call(this, config);
40465 * Fires when the autosize function is triggered. The field may or may not have actually changed size
40466 * according to the default logic, but this event provides a hook for the developer to apply additional
40467 * logic at runtime to resize the field if needed.
40468 * @param {Roo.form.Field} this This text field
40469 * @param {Number} width The new field width
40475 Roo.extend(Roo.form.TextField, Roo.form.Field, {
40477 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
40481 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
40485 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
40489 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
40493 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
40497 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
40499 disableKeyFilter : false,
40501 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
40505 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
40509 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
40511 maxLength : Number.MAX_VALUE,
40513 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
40515 minLengthText : "The minimum length for this field is {0}",
40517 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
40519 maxLengthText : "The maximum length for this field is {0}",
40521 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
40523 selectOnFocus : false,
40525 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
40527 allowLeadingSpace : false,
40529 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
40531 blankText : "This field is required",
40533 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
40534 * If available, this function will be called only after the basic validators all return true, and will be passed the
40535 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
40539 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
40540 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
40541 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
40545 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
40549 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
40555 initEvents : function()
40557 if (this.emptyText) {
40558 this.el.attr('placeholder', this.emptyText);
40561 Roo.form.TextField.superclass.initEvents.call(this);
40562 if(this.validationEvent == 'keyup'){
40563 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40564 this.el.on('keyup', this.filterValidation, this);
40566 else if(this.validationEvent !== false){
40567 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40570 if(this.selectOnFocus){
40571 this.on("focus", this.preFocus, this);
40573 if (!this.allowLeadingSpace) {
40574 this.on('blur', this.cleanLeadingSpace, this);
40577 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40578 this.el.on("keypress", this.filterKeys, this);
40581 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
40582 this.el.on("click", this.autoSize, this);
40584 if(this.el.is('input[type=password]') && Roo.isSafari){
40585 this.el.on('keydown', this.SafariOnKeyDown, this);
40589 processValue : function(value){
40590 if(this.stripCharsRe){
40591 var newValue = value.replace(this.stripCharsRe, '');
40592 if(newValue !== value){
40593 this.setRawValue(newValue);
40600 filterValidation : function(e){
40601 if(!e.isNavKeyPress()){
40602 this.validationTask.delay(this.validationDelay);
40607 onKeyUp : function(e){
40608 if(!e.isNavKeyPress()){
40612 // private - clean the leading white space
40613 cleanLeadingSpace : function(e)
40615 if ( this.inputType == 'file') {
40619 this.setValue((this.getValue() + '').replace(/^\s+/,''));
40622 * Resets the current field value to the originally-loaded value and clears any validation messages.
40625 reset : function(){
40626 Roo.form.TextField.superclass.reset.call(this);
40630 preFocus : function(){
40632 if(this.selectOnFocus){
40633 this.el.dom.select();
40639 filterKeys : function(e){
40640 var k = e.getKey();
40641 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
40644 var c = e.getCharCode(), cc = String.fromCharCode(c);
40645 if(Roo.isIE && (e.isSpecialKey() || !cc)){
40648 if(!this.maskRe.test(cc)){
40653 setValue : function(v){
40655 Roo.form.TextField.superclass.setValue.apply(this, arguments);
40661 * Validates a value according to the field's validation rules and marks the field as invalid
40662 * if the validation fails
40663 * @param {Mixed} value The value to validate
40664 * @return {Boolean} True if the value is valid, else false
40666 validateValue : function(value){
40667 if(value.length < 1) { // if it's blank
40668 if(this.allowBlank){
40669 this.clearInvalid();
40672 this.markInvalid(this.blankText);
40676 if(value.length < this.minLength){
40677 this.markInvalid(String.format(this.minLengthText, this.minLength));
40680 if(value.length > this.maxLength){
40681 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
40685 var vt = Roo.form.VTypes;
40686 if(!vt[this.vtype](value, this)){
40687 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
40691 if(typeof this.validator == "function"){
40692 var msg = this.validator(value);
40694 this.markInvalid(msg);
40698 if(this.regex && !this.regex.test(value)){
40699 this.markInvalid(this.regexText);
40706 * Selects text in this field
40707 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
40708 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
40710 selectText : function(start, end){
40711 var v = this.getRawValue();
40713 start = start === undefined ? 0 : start;
40714 end = end === undefined ? v.length : end;
40715 var d = this.el.dom;
40716 if(d.setSelectionRange){
40717 d.setSelectionRange(start, end);
40718 }else if(d.createTextRange){
40719 var range = d.createTextRange();
40720 range.moveStart("character", start);
40721 range.moveEnd("character", v.length-end);
40728 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
40729 * This only takes effect if grow = true, and fires the autosize event.
40731 autoSize : function(){
40732 if(!this.grow || !this.rendered){
40736 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
40739 var v = el.dom.value;
40740 var d = document.createElement('div');
40741 d.appendChild(document.createTextNode(v));
40745 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
40746 this.el.setWidth(w);
40747 this.fireEvent("autosize", this, w);
40751 SafariOnKeyDown : function(event)
40753 // this is a workaround for a password hang bug on chrome/ webkit.
40755 var isSelectAll = false;
40757 if(this.el.dom.selectionEnd > 0){
40758 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
40760 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
40761 event.preventDefault();
40766 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
40768 event.preventDefault();
40769 // this is very hacky as keydown always get's upper case.
40771 var cc = String.fromCharCode(event.getCharCode());
40774 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
40782 * Ext JS Library 1.1.1
40783 * Copyright(c) 2006-2007, Ext JS, LLC.
40785 * Originally Released Under LGPL - original licence link has changed is not relivant.
40788 * <script type="text/javascript">
40792 * @class Roo.form.Hidden
40793 * @extends Roo.form.TextField
40794 * Simple Hidden element used on forms
40796 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
40799 * Creates a new Hidden form element.
40800 * @param {Object} config Configuration options
40805 // easy hidden field...
40806 Roo.form.Hidden = function(config){
40807 Roo.form.Hidden.superclass.constructor.call(this, config);
40810 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
40812 inputType: 'hidden',
40815 labelSeparator: '',
40817 itemCls : 'x-form-item-display-none'
40825 * Ext JS Library 1.1.1
40826 * Copyright(c) 2006-2007, Ext JS, LLC.
40828 * Originally Released Under LGPL - original licence link has changed is not relivant.
40831 * <script type="text/javascript">
40835 * @class Roo.form.TriggerField
40836 * @extends Roo.form.TextField
40837 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
40838 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
40839 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
40840 * for which you can provide a custom implementation. For example:
40842 var trigger = new Roo.form.TriggerField();
40843 trigger.onTriggerClick = myTriggerFn;
40844 trigger.applyTo('my-field');
40847 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
40848 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
40849 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40850 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
40852 * Create a new TriggerField.
40853 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
40854 * to the base TextField)
40856 Roo.form.TriggerField = function(config){
40857 this.mimicing = false;
40858 Roo.form.TriggerField.superclass.constructor.call(this, config);
40861 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
40863 * @cfg {String} triggerClass A CSS class to apply to the trigger
40866 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40867 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
40869 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
40871 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
40875 /** @cfg {Boolean} grow @hide */
40876 /** @cfg {Number} growMin @hide */
40877 /** @cfg {Number} growMax @hide */
40883 autoSize: Roo.emptyFn,
40887 deferHeight : true,
40890 actionMode : 'wrap',
40892 onResize : function(w, h){
40893 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
40894 if(typeof w == 'number'){
40895 var x = w - this.trigger.getWidth();
40896 this.el.setWidth(this.adjustWidth('input', x));
40897 this.trigger.setStyle('left', x+'px');
40902 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40905 getResizeEl : function(){
40910 getPositionEl : function(){
40915 alignErrorIcon : function(){
40916 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40920 onRender : function(ct, position){
40921 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40922 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
40923 this.trigger = this.wrap.createChild(this.triggerConfig ||
40924 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
40925 if(this.hideTrigger){
40926 this.trigger.setDisplayed(false);
40928 this.initTrigger();
40930 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
40935 initTrigger : function(){
40936 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40937 this.trigger.addClassOnOver('x-form-trigger-over');
40938 this.trigger.addClassOnClick('x-form-trigger-click');
40942 onDestroy : function(){
40944 this.trigger.removeAllListeners();
40945 this.trigger.remove();
40948 this.wrap.remove();
40950 Roo.form.TriggerField.superclass.onDestroy.call(this);
40954 onFocus : function(){
40955 Roo.form.TriggerField.superclass.onFocus.call(this);
40956 if(!this.mimicing){
40957 this.wrap.addClass('x-trigger-wrap-focus');
40958 this.mimicing = true;
40959 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40960 if(this.monitorTab){
40961 this.el.on("keydown", this.checkTab, this);
40967 checkTab : function(e){
40968 if(e.getKey() == e.TAB){
40969 this.triggerBlur();
40974 onBlur : function(){
40979 mimicBlur : function(e, t){
40980 if(!this.wrap.contains(t) && this.validateBlur()){
40981 this.triggerBlur();
40986 triggerBlur : function(){
40987 this.mimicing = false;
40988 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40989 if(this.monitorTab){
40990 this.el.un("keydown", this.checkTab, this);
40992 this.wrap.removeClass('x-trigger-wrap-focus');
40993 Roo.form.TriggerField.superclass.onBlur.call(this);
40997 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40998 validateBlur : function(e, t){
41003 onDisable : function(){
41004 Roo.form.TriggerField.superclass.onDisable.call(this);
41006 this.wrap.addClass('x-item-disabled');
41011 onEnable : function(){
41012 Roo.form.TriggerField.superclass.onEnable.call(this);
41014 this.wrap.removeClass('x-item-disabled');
41019 onShow : function(){
41020 var ae = this.getActionEl();
41023 ae.dom.style.display = '';
41024 ae.dom.style.visibility = 'visible';
41030 onHide : function(){
41031 var ae = this.getActionEl();
41032 ae.dom.style.display = 'none';
41036 * The function that should handle the trigger's click event. This method does nothing by default until overridden
41037 * by an implementing function.
41039 * @param {EventObject} e
41041 onTriggerClick : Roo.emptyFn
41044 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
41045 // to be extended by an implementing class. For an example of implementing this class, see the custom
41046 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
41047 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
41048 initComponent : function(){
41049 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
41051 this.triggerConfig = {
41052 tag:'span', cls:'x-form-twin-triggers', cn:[
41053 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
41054 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
41058 getTrigger : function(index){
41059 return this.triggers[index];
41062 initTrigger : function(){
41063 var ts = this.trigger.select('.x-form-trigger', true);
41064 this.wrap.setStyle('overflow', 'hidden');
41065 var triggerField = this;
41066 ts.each(function(t, all, index){
41067 t.hide = function(){
41068 var w = triggerField.wrap.getWidth();
41069 this.dom.style.display = 'none';
41070 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
41072 t.show = function(){
41073 var w = triggerField.wrap.getWidth();
41074 this.dom.style.display = '';
41075 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
41077 var triggerIndex = 'Trigger'+(index+1);
41079 if(this['hide'+triggerIndex]){
41080 t.dom.style.display = 'none';
41082 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
41083 t.addClassOnOver('x-form-trigger-over');
41084 t.addClassOnClick('x-form-trigger-click');
41086 this.triggers = ts.elements;
41089 onTrigger1Click : Roo.emptyFn,
41090 onTrigger2Click : Roo.emptyFn
41093 * Ext JS Library 1.1.1
41094 * Copyright(c) 2006-2007, Ext JS, LLC.
41096 * Originally Released Under LGPL - original licence link has changed is not relivant.
41099 * <script type="text/javascript">
41103 * @class Roo.form.TextArea
41104 * @extends Roo.form.TextField
41105 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
41106 * support for auto-sizing.
41108 * Creates a new TextArea
41109 * @param {Object} config Configuration options
41111 Roo.form.TextArea = function(config){
41112 Roo.form.TextArea.superclass.constructor.call(this, config);
41113 // these are provided exchanges for backwards compat
41114 // minHeight/maxHeight were replaced by growMin/growMax to be
41115 // compatible with TextField growing config values
41116 if(this.minHeight !== undefined){
41117 this.growMin = this.minHeight;
41119 if(this.maxHeight !== undefined){
41120 this.growMax = this.maxHeight;
41124 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
41126 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
41130 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
41134 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
41135 * in the field (equivalent to setting overflow: hidden, defaults to false)
41137 preventScrollbars: false,
41139 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41140 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
41144 onRender : function(ct, position){
41146 this.defaultAutoCreate = {
41148 style:"width:300px;height:60px;",
41149 autocomplete: "new-password"
41152 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
41154 this.textSizeEl = Roo.DomHelper.append(document.body, {
41155 tag: "pre", cls: "x-form-grow-sizer"
41157 if(this.preventScrollbars){
41158 this.el.setStyle("overflow", "hidden");
41160 this.el.setHeight(this.growMin);
41164 onDestroy : function(){
41165 if(this.textSizeEl){
41166 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
41168 Roo.form.TextArea.superclass.onDestroy.call(this);
41172 onKeyUp : function(e){
41173 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
41179 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
41180 * This only takes effect if grow = true, and fires the autosize event if the height changes.
41182 autoSize : function(){
41183 if(!this.grow || !this.textSizeEl){
41187 var v = el.dom.value;
41188 var ts = this.textSizeEl;
41191 ts.appendChild(document.createTextNode(v));
41194 Roo.fly(ts).setWidth(this.el.getWidth());
41196 v = "  ";
41199 v = v.replace(/\n/g, '<p> </p>');
41201 v += " \n ";
41204 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
41205 if(h != this.lastHeight){
41206 this.lastHeight = h;
41207 this.el.setHeight(h);
41208 this.fireEvent("autosize", this, h);
41213 * Ext JS Library 1.1.1
41214 * Copyright(c) 2006-2007, Ext JS, LLC.
41216 * Originally Released Under LGPL - original licence link has changed is not relivant.
41219 * <script type="text/javascript">
41224 * @class Roo.form.NumberField
41225 * @extends Roo.form.TextField
41226 * Numeric text field that provides automatic keystroke filtering and numeric validation.
41228 * Creates a new NumberField
41229 * @param {Object} config Configuration options
41231 Roo.form.NumberField = function(config){
41232 Roo.form.NumberField.superclass.constructor.call(this, config);
41235 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
41237 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
41239 fieldClass: "x-form-field x-form-num-field",
41241 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
41243 allowDecimals : true,
41245 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
41247 decimalSeparator : ".",
41249 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
41251 decimalPrecision : 2,
41253 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
41255 allowNegative : true,
41257 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
41259 minValue : Number.NEGATIVE_INFINITY,
41261 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
41263 maxValue : Number.MAX_VALUE,
41265 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
41267 minText : "The minimum value for this field is {0}",
41269 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
41271 maxText : "The maximum value for this field is {0}",
41273 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
41274 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
41276 nanText : "{0} is not a valid number",
41279 initEvents : function(){
41280 Roo.form.NumberField.superclass.initEvents.call(this);
41281 var allowed = "0123456789";
41282 if(this.allowDecimals){
41283 allowed += this.decimalSeparator;
41285 if(this.allowNegative){
41288 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41289 var keyPress = function(e){
41290 var k = e.getKey();
41291 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41294 var c = e.getCharCode();
41295 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41299 this.el.on("keypress", keyPress, this);
41303 validateValue : function(value){
41304 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
41307 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41310 var num = this.parseValue(value);
41312 this.markInvalid(String.format(this.nanText, value));
41315 if(num < this.minValue){
41316 this.markInvalid(String.format(this.minText, this.minValue));
41319 if(num > this.maxValue){
41320 this.markInvalid(String.format(this.maxText, this.maxValue));
41326 getValue : function(){
41327 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
41331 parseValue : function(value){
41332 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41333 return isNaN(value) ? '' : value;
41337 fixPrecision : function(value){
41338 var nan = isNaN(value);
41339 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41340 return nan ? '' : value;
41342 return parseFloat(value).toFixed(this.decimalPrecision);
41345 setValue : function(v){
41346 v = this.fixPrecision(v);
41347 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
41351 decimalPrecisionFcn : function(v){
41352 return Math.floor(v);
41355 beforeBlur : function(){
41356 var v = this.parseValue(this.getRawValue());
41363 * Ext JS Library 1.1.1
41364 * Copyright(c) 2006-2007, Ext JS, LLC.
41366 * Originally Released Under LGPL - original licence link has changed is not relivant.
41369 * <script type="text/javascript">
41373 * @class Roo.form.DateField
41374 * @extends Roo.form.TriggerField
41375 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
41377 * Create a new DateField
41378 * @param {Object} config
41380 Roo.form.DateField = function(config)
41382 Roo.form.DateField.superclass.constructor.call(this, config);
41388 * Fires when a date is selected
41389 * @param {Roo.form.DateField} combo This combo box
41390 * @param {Date} date The date selected
41397 if(typeof this.minValue == "string") {
41398 this.minValue = this.parseDate(this.minValue);
41400 if(typeof this.maxValue == "string") {
41401 this.maxValue = this.parseDate(this.maxValue);
41403 this.ddMatch = null;
41404 if(this.disabledDates){
41405 var dd = this.disabledDates;
41407 for(var i = 0; i < dd.length; i++){
41409 if(i != dd.length-1) {
41413 this.ddMatch = new RegExp(re + ")");
41417 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
41419 * @cfg {String} format
41420 * The default date format string which can be overriden for localization support. The format must be
41421 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41425 * @cfg {String} altFormats
41426 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
41427 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
41429 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
41431 * @cfg {Array} disabledDays
41432 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41434 disabledDays : null,
41436 * @cfg {String} disabledDaysText
41437 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41439 disabledDaysText : "Disabled",
41441 * @cfg {Array} disabledDates
41442 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41443 * expression so they are very powerful. Some examples:
41445 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41446 * <li>["03/08", "09/16"] would disable those days for every year</li>
41447 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41448 * <li>["03/../2006"] would disable every day in March 2006</li>
41449 * <li>["^03"] would disable every day in every March</li>
41451 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41452 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41454 disabledDates : null,
41456 * @cfg {String} disabledDatesText
41457 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41459 disabledDatesText : "Disabled",
41461 * @cfg {Date/String} minValue
41462 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41463 * valid format (defaults to null).
41467 * @cfg {Date/String} maxValue
41468 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41469 * valid format (defaults to null).
41473 * @cfg {String} minText
41474 * The error text to display when the date in the cell is before minValue (defaults to
41475 * 'The date in this field must be after {minValue}').
41477 minText : "The date in this field must be equal to or after {0}",
41479 * @cfg {String} maxText
41480 * The error text to display when the date in the cell is after maxValue (defaults to
41481 * 'The date in this field must be before {maxValue}').
41483 maxText : "The date in this field must be equal to or before {0}",
41485 * @cfg {String} invalidText
41486 * The error text to display when the date in the field is invalid (defaults to
41487 * '{value} is not a valid date - it must be in the format {format}').
41489 invalidText : "{0} is not a valid date - it must be in the format {1}",
41491 * @cfg {String} triggerClass
41492 * An additional CSS class used to style the trigger button. The trigger will always get the
41493 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41494 * which displays a calendar icon).
41496 triggerClass : 'x-form-date-trigger',
41500 * @cfg {Boolean} useIso
41501 * if enabled, then the date field will use a hidden field to store the
41502 * real value as iso formated date. default (false)
41506 * @cfg {String/Object} autoCreate
41507 * A DomHelper element spec, or true for a default element spec (defaults to
41508 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41511 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
41514 hiddenField: false,
41516 onRender : function(ct, position)
41518 Roo.form.DateField.superclass.onRender.call(this, ct, position);
41520 //this.el.dom.removeAttribute('name');
41521 Roo.log("Changing name?");
41522 this.el.dom.setAttribute('name', this.name + '____hidden___' );
41523 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41525 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41526 // prevent input submission
41527 this.hiddenName = this.name;
41534 validateValue : function(value)
41536 value = this.formatDate(value);
41537 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
41538 Roo.log('super failed');
41541 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41544 var svalue = value;
41545 value = this.parseDate(value);
41547 Roo.log('parse date failed' + svalue);
41548 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41551 var time = value.getTime();
41552 if(this.minValue && time < this.minValue.getTime()){
41553 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41556 if(this.maxValue && time > this.maxValue.getTime()){
41557 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41560 if(this.disabledDays){
41561 var day = value.getDay();
41562 for(var i = 0; i < this.disabledDays.length; i++) {
41563 if(day === this.disabledDays[i]){
41564 this.markInvalid(this.disabledDaysText);
41569 var fvalue = this.formatDate(value);
41570 if(this.ddMatch && this.ddMatch.test(fvalue)){
41571 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41578 // Provides logic to override the default TriggerField.validateBlur which just returns true
41579 validateBlur : function(){
41580 return !this.menu || !this.menu.isVisible();
41583 getName: function()
41585 // returns hidden if it's set..
41586 if (!this.rendered) {return ''};
41587 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41592 * Returns the current date value of the date field.
41593 * @return {Date} The date value
41595 getValue : function(){
41597 return this.hiddenField ?
41598 this.hiddenField.value :
41599 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
41603 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41604 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
41605 * (the default format used is "m/d/y").
41608 //All of these calls set the same date value (May 4, 2006)
41610 //Pass a date object:
41611 var dt = new Date('5/4/06');
41612 dateField.setValue(dt);
41614 //Pass a date string (default format):
41615 dateField.setValue('5/4/06');
41617 //Pass a date string (custom format):
41618 dateField.format = 'Y-m-d';
41619 dateField.setValue('2006-5-4');
41621 * @param {String/Date} date The date or valid date string
41623 setValue : function(date){
41624 if (this.hiddenField) {
41625 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41627 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41628 // make sure the value field is always stored as a date..
41629 this.value = this.parseDate(date);
41635 parseDate : function(value){
41636 if(!value || value instanceof Date){
41639 var v = Date.parseDate(value, this.format);
41640 if (!v && this.useIso) {
41641 v = Date.parseDate(value, 'Y-m-d');
41643 if(!v && this.altFormats){
41644 if(!this.altFormatsArray){
41645 this.altFormatsArray = this.altFormats.split("|");
41647 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41648 v = Date.parseDate(value, this.altFormatsArray[i]);
41655 formatDate : function(date, fmt){
41656 return (!date || !(date instanceof Date)) ?
41657 date : date.dateFormat(fmt || this.format);
41662 select: function(m, d){
41665 this.fireEvent('select', this, d);
41667 show : function(){ // retain focus styling
41671 this.focus.defer(10, this);
41672 var ml = this.menuListeners;
41673 this.menu.un("select", ml.select, this);
41674 this.menu.un("show", ml.show, this);
41675 this.menu.un("hide", ml.hide, this);
41680 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41681 onTriggerClick : function(){
41685 if(this.menu == null){
41686 this.menu = new Roo.menu.DateMenu();
41688 Roo.apply(this.menu.picker, {
41689 showClear: this.allowBlank,
41690 minDate : this.minValue,
41691 maxDate : this.maxValue,
41692 disabledDatesRE : this.ddMatch,
41693 disabledDatesText : this.disabledDatesText,
41694 disabledDays : this.disabledDays,
41695 disabledDaysText : this.disabledDaysText,
41696 format : this.useIso ? 'Y-m-d' : this.format,
41697 minText : String.format(this.minText, this.formatDate(this.minValue)),
41698 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41700 this.menu.on(Roo.apply({}, this.menuListeners, {
41703 this.menu.picker.setValue(this.getValue() || new Date());
41704 this.menu.show(this.el, "tl-bl?");
41707 beforeBlur : function(){
41708 var v = this.parseDate(this.getRawValue());
41718 isDirty : function() {
41719 if(this.disabled) {
41723 if(typeof(this.startValue) === 'undefined'){
41727 return String(this.getValue()) !== String(this.startValue);
41731 cleanLeadingSpace : function(e)
41738 * Ext JS Library 1.1.1
41739 * Copyright(c) 2006-2007, Ext JS, LLC.
41741 * Originally Released Under LGPL - original licence link has changed is not relivant.
41744 * <script type="text/javascript">
41748 * @class Roo.form.MonthField
41749 * @extends Roo.form.TriggerField
41750 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
41752 * Create a new MonthField
41753 * @param {Object} config
41755 Roo.form.MonthField = function(config){
41757 Roo.form.MonthField.superclass.constructor.call(this, config);
41763 * Fires when a date is selected
41764 * @param {Roo.form.MonthFieeld} combo This combo box
41765 * @param {Date} date The date selected
41772 if(typeof this.minValue == "string") {
41773 this.minValue = this.parseDate(this.minValue);
41775 if(typeof this.maxValue == "string") {
41776 this.maxValue = this.parseDate(this.maxValue);
41778 this.ddMatch = null;
41779 if(this.disabledDates){
41780 var dd = this.disabledDates;
41782 for(var i = 0; i < dd.length; i++){
41784 if(i != dd.length-1) {
41788 this.ddMatch = new RegExp(re + ")");
41792 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
41794 * @cfg {String} format
41795 * The default date format string which can be overriden for localization support. The format must be
41796 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41800 * @cfg {String} altFormats
41801 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
41802 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
41804 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
41806 * @cfg {Array} disabledDays
41807 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41809 disabledDays : [0,1,2,3,4,5,6],
41811 * @cfg {String} disabledDaysText
41812 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41814 disabledDaysText : "Disabled",
41816 * @cfg {Array} disabledDates
41817 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41818 * expression so they are very powerful. Some examples:
41820 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41821 * <li>["03/08", "09/16"] would disable those days for every year</li>
41822 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41823 * <li>["03/../2006"] would disable every day in March 2006</li>
41824 * <li>["^03"] would disable every day in every March</li>
41826 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41827 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41829 disabledDates : null,
41831 * @cfg {String} disabledDatesText
41832 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41834 disabledDatesText : "Disabled",
41836 * @cfg {Date/String} minValue
41837 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41838 * valid format (defaults to null).
41842 * @cfg {Date/String} maxValue
41843 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41844 * valid format (defaults to null).
41848 * @cfg {String} minText
41849 * The error text to display when the date in the cell is before minValue (defaults to
41850 * 'The date in this field must be after {minValue}').
41852 minText : "The date in this field must be equal to or after {0}",
41854 * @cfg {String} maxTextf
41855 * The error text to display when the date in the cell is after maxValue (defaults to
41856 * 'The date in this field must be before {maxValue}').
41858 maxText : "The date in this field must be equal to or before {0}",
41860 * @cfg {String} invalidText
41861 * The error text to display when the date in the field is invalid (defaults to
41862 * '{value} is not a valid date - it must be in the format {format}').
41864 invalidText : "{0} is not a valid date - it must be in the format {1}",
41866 * @cfg {String} triggerClass
41867 * An additional CSS class used to style the trigger button. The trigger will always get the
41868 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41869 * which displays a calendar icon).
41871 triggerClass : 'x-form-date-trigger',
41875 * @cfg {Boolean} useIso
41876 * if enabled, then the date field will use a hidden field to store the
41877 * real value as iso formated date. default (true)
41881 * @cfg {String/Object} autoCreate
41882 * A DomHelper element spec, or true for a default element spec (defaults to
41883 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41886 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
41889 hiddenField: false,
41891 hideMonthPicker : false,
41893 onRender : function(ct, position)
41895 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
41897 this.el.dom.removeAttribute('name');
41898 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41900 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41901 // prevent input submission
41902 this.hiddenName = this.name;
41909 validateValue : function(value)
41911 value = this.formatDate(value);
41912 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41915 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41918 var svalue = value;
41919 value = this.parseDate(value);
41921 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41924 var time = value.getTime();
41925 if(this.minValue && time < this.minValue.getTime()){
41926 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41929 if(this.maxValue && time > this.maxValue.getTime()){
41930 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41933 /*if(this.disabledDays){
41934 var day = value.getDay();
41935 for(var i = 0; i < this.disabledDays.length; i++) {
41936 if(day === this.disabledDays[i]){
41937 this.markInvalid(this.disabledDaysText);
41943 var fvalue = this.formatDate(value);
41944 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41945 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41953 // Provides logic to override the default TriggerField.validateBlur which just returns true
41954 validateBlur : function(){
41955 return !this.menu || !this.menu.isVisible();
41959 * Returns the current date value of the date field.
41960 * @return {Date} The date value
41962 getValue : function(){
41966 return this.hiddenField ?
41967 this.hiddenField.value :
41968 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41972 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41973 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41974 * (the default format used is "m/d/y").
41977 //All of these calls set the same date value (May 4, 2006)
41979 //Pass a date object:
41980 var dt = new Date('5/4/06');
41981 monthField.setValue(dt);
41983 //Pass a date string (default format):
41984 monthField.setValue('5/4/06');
41986 //Pass a date string (custom format):
41987 monthField.format = 'Y-m-d';
41988 monthField.setValue('2006-5-4');
41990 * @param {String/Date} date The date or valid date string
41992 setValue : function(date){
41993 Roo.log('month setValue' + date);
41994 // can only be first of month..
41996 var val = this.parseDate(date);
41998 if (this.hiddenField) {
41999 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
42001 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
42002 this.value = this.parseDate(date);
42006 parseDate : function(value){
42007 if(!value || value instanceof Date){
42008 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
42011 var v = Date.parseDate(value, this.format);
42012 if (!v && this.useIso) {
42013 v = Date.parseDate(value, 'Y-m-d');
42017 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
42021 if(!v && this.altFormats){
42022 if(!this.altFormatsArray){
42023 this.altFormatsArray = this.altFormats.split("|");
42025 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
42026 v = Date.parseDate(value, this.altFormatsArray[i]);
42033 formatDate : function(date, fmt){
42034 return (!date || !(date instanceof Date)) ?
42035 date : date.dateFormat(fmt || this.format);
42040 select: function(m, d){
42042 this.fireEvent('select', this, d);
42044 show : function(){ // retain focus styling
42048 this.focus.defer(10, this);
42049 var ml = this.menuListeners;
42050 this.menu.un("select", ml.select, this);
42051 this.menu.un("show", ml.show, this);
42052 this.menu.un("hide", ml.hide, this);
42056 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
42057 onTriggerClick : function(){
42061 if(this.menu == null){
42062 this.menu = new Roo.menu.DateMenu();
42066 Roo.apply(this.menu.picker, {
42068 showClear: this.allowBlank,
42069 minDate : this.minValue,
42070 maxDate : this.maxValue,
42071 disabledDatesRE : this.ddMatch,
42072 disabledDatesText : this.disabledDatesText,
42074 format : this.useIso ? 'Y-m-d' : this.format,
42075 minText : String.format(this.minText, this.formatDate(this.minValue)),
42076 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
42079 this.menu.on(Roo.apply({}, this.menuListeners, {
42087 // hide month picker get's called when we called by 'before hide';
42089 var ignorehide = true;
42090 p.hideMonthPicker = function(disableAnim){
42094 if(this.monthPicker){
42095 Roo.log("hideMonthPicker called");
42096 if(disableAnim === true){
42097 this.monthPicker.hide();
42099 this.monthPicker.slideOut('t', {duration:.2});
42100 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
42101 p.fireEvent("select", this, this.value);
42107 Roo.log('picker set value');
42108 Roo.log(this.getValue());
42109 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
42110 m.show(this.el, 'tl-bl?');
42111 ignorehide = false;
42112 // this will trigger hideMonthPicker..
42115 // hidden the day picker
42116 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
42122 p.showMonthPicker.defer(100, p);
42128 beforeBlur : function(){
42129 var v = this.parseDate(this.getRawValue());
42135 /** @cfg {Boolean} grow @hide */
42136 /** @cfg {Number} growMin @hide */
42137 /** @cfg {Number} growMax @hide */
42144 * Ext JS Library 1.1.1
42145 * Copyright(c) 2006-2007, Ext JS, LLC.
42147 * Originally Released Under LGPL - original licence link has changed is not relivant.
42150 * <script type="text/javascript">
42155 * @class Roo.form.ComboBox
42156 * @extends Roo.form.TriggerField
42157 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
42159 * Create a new ComboBox.
42160 * @param {Object} config Configuration options
42162 Roo.form.ComboBox = function(config){
42163 Roo.form.ComboBox.superclass.constructor.call(this, config);
42167 * Fires when the dropdown list is expanded
42168 * @param {Roo.form.ComboBox} combo This combo box
42173 * Fires when the dropdown list is collapsed
42174 * @param {Roo.form.ComboBox} combo This combo box
42178 * @event beforeselect
42179 * Fires before a list item is selected. Return false to cancel the selection.
42180 * @param {Roo.form.ComboBox} combo This combo box
42181 * @param {Roo.data.Record} record The data record returned from the underlying store
42182 * @param {Number} index The index of the selected item in the dropdown list
42184 'beforeselect' : true,
42187 * Fires when a list item is selected
42188 * @param {Roo.form.ComboBox} combo This combo box
42189 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
42190 * @param {Number} index The index of the selected item in the dropdown list
42194 * @event beforequery
42195 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
42196 * The event object passed has these properties:
42197 * @param {Roo.form.ComboBox} combo This combo box
42198 * @param {String} query The query
42199 * @param {Boolean} forceAll true to force "all" query
42200 * @param {Boolean} cancel true to cancel the query
42201 * @param {Object} e The query event object
42203 'beforequery': true,
42206 * Fires when the 'add' icon is pressed (add a listener to enable add button)
42207 * @param {Roo.form.ComboBox} combo This combo box
42212 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
42213 * @param {Roo.form.ComboBox} combo This combo box
42214 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
42220 if(this.transform){
42221 this.allowDomMove = false;
42222 var s = Roo.getDom(this.transform);
42223 if(!this.hiddenName){
42224 this.hiddenName = s.name;
42227 this.mode = 'local';
42228 var d = [], opts = s.options;
42229 for(var i = 0, len = opts.length;i < len; i++){
42231 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
42233 this.value = value;
42235 d.push([value, o.text]);
42237 this.store = new Roo.data.SimpleStore({
42239 fields: ['value', 'text'],
42242 this.valueField = 'value';
42243 this.displayField = 'text';
42245 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
42246 if(!this.lazyRender){
42247 this.target = true;
42248 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
42249 s.parentNode.removeChild(s); // remove it
42250 this.render(this.el.parentNode);
42252 s.parentNode.removeChild(s); // remove it
42257 this.store = Roo.factory(this.store, Roo.data);
42260 this.selectedIndex = -1;
42261 if(this.mode == 'local'){
42262 if(config.queryDelay === undefined){
42263 this.queryDelay = 10;
42265 if(config.minChars === undefined){
42271 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
42273 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
42276 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
42277 * rendering into an Roo.Editor, defaults to false)
42280 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
42281 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
42284 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
42287 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
42288 * the dropdown list (defaults to undefined, with no header element)
42292 * @cfg {String/Roo.Template} tpl The template to use to render the output
42296 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
42298 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
42300 listWidth: undefined,
42302 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
42303 * mode = 'remote' or 'text' if mode = 'local')
42305 displayField: undefined,
42307 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
42308 * mode = 'remote' or 'value' if mode = 'local').
42309 * Note: use of a valueField requires the user make a selection
42310 * in order for a value to be mapped.
42312 valueField: undefined,
42316 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
42317 * field's data value (defaults to the underlying DOM element's name)
42319 hiddenName: undefined,
42321 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
42325 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
42327 selectedClass: 'x-combo-selected',
42329 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
42330 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
42331 * which displays a downward arrow icon).
42333 triggerClass : 'x-form-arrow-trigger',
42335 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
42339 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
42340 * anchor positions (defaults to 'tl-bl')
42342 listAlign: 'tl-bl?',
42344 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
42348 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
42349 * query specified by the allQuery config option (defaults to 'query')
42351 triggerAction: 'query',
42353 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
42354 * (defaults to 4, does not apply if editable = false)
42358 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
42359 * delay (typeAheadDelay) if it matches a known value (defaults to false)
42363 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
42364 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
42368 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
42369 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
42373 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
42374 * when editable = true (defaults to false)
42376 selectOnFocus:false,
42378 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
42380 queryParam: 'query',
42382 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
42383 * when mode = 'remote' (defaults to 'Loading...')
42385 loadingText: 'Loading...',
42387 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
42391 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
42395 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
42396 * traditional select (defaults to true)
42400 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
42404 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
42408 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
42409 * listWidth has a higher value)
42413 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
42414 * allow the user to set arbitrary text into the field (defaults to false)
42416 forceSelection:false,
42418 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
42419 * if typeAhead = true (defaults to 250)
42421 typeAheadDelay : 250,
42423 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
42424 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
42426 valueNotFoundText : undefined,
42428 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
42430 blockFocus : false,
42433 * @cfg {Boolean} disableClear Disable showing of clear button.
42435 disableClear : false,
42437 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
42439 alwaysQuery : false,
42445 // element that contains real text value.. (when hidden is used..)
42448 onRender : function(ct, position)
42450 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
42452 if(this.hiddenName){
42453 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42455 this.hiddenField.value =
42456 this.hiddenValue !== undefined ? this.hiddenValue :
42457 this.value !== undefined ? this.value : '';
42459 // prevent input submission
42460 this.el.dom.removeAttribute('name');
42466 this.el.dom.setAttribute('autocomplete', 'off');
42469 var cls = 'x-combo-list';
42471 this.list = new Roo.Layer({
42472 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
42475 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
42476 this.list.setWidth(lw);
42477 this.list.swallowEvent('mousewheel');
42478 this.assetHeight = 0;
42481 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
42482 this.assetHeight += this.header.getHeight();
42485 this.innerList = this.list.createChild({cls:cls+'-inner'});
42486 this.innerList.on('mouseover', this.onViewOver, this);
42487 this.innerList.on('mousemove', this.onViewMove, this);
42488 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42490 if(this.allowBlank && !this.pageSize && !this.disableClear){
42491 this.footer = this.list.createChild({cls:cls+'-ft'});
42492 this.pageTb = new Roo.Toolbar(this.footer);
42496 this.footer = this.list.createChild({cls:cls+'-ft'});
42497 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
42498 {pageSize: this.pageSize});
42502 if (this.pageTb && this.allowBlank && !this.disableClear) {
42504 this.pageTb.add(new Roo.Toolbar.Fill(), {
42505 cls: 'x-btn-icon x-btn-clear',
42507 handler: function()
42510 _this.clearValue();
42511 _this.onSelect(false, -1);
42516 this.assetHeight += this.footer.getHeight();
42521 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
42524 this.view = new Roo.View(this.innerList, this.tpl, {
42527 selectedClass: this.selectedClass
42530 this.view.on('click', this.onViewClick, this);
42532 this.store.on('beforeload', this.onBeforeLoad, this);
42533 this.store.on('load', this.onLoad, this);
42534 this.store.on('loadexception', this.onLoadException, this);
42536 if(this.resizable){
42537 this.resizer = new Roo.Resizable(this.list, {
42538 pinned:true, handles:'se'
42540 this.resizer.on('resize', function(r, w, h){
42541 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
42542 this.listWidth = w;
42543 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
42544 this.restrictHeight();
42546 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
42548 if(!this.editable){
42549 this.editable = true;
42550 this.setEditable(false);
42554 if (typeof(this.events.add.listeners) != 'undefined') {
42556 this.addicon = this.wrap.createChild(
42557 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
42559 this.addicon.on('click', function(e) {
42560 this.fireEvent('add', this);
42563 if (typeof(this.events.edit.listeners) != 'undefined') {
42565 this.editicon = this.wrap.createChild(
42566 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
42567 if (this.addicon) {
42568 this.editicon.setStyle('margin-left', '40px');
42570 this.editicon.on('click', function(e) {
42572 // we fire even if inothing is selected..
42573 this.fireEvent('edit', this, this.lastData );
42583 initEvents : function(){
42584 Roo.form.ComboBox.superclass.initEvents.call(this);
42586 this.keyNav = new Roo.KeyNav(this.el, {
42587 "up" : function(e){
42588 this.inKeyMode = true;
42592 "down" : function(e){
42593 if(!this.isExpanded()){
42594 this.onTriggerClick();
42596 this.inKeyMode = true;
42601 "enter" : function(e){
42602 this.onViewClick();
42606 "esc" : function(e){
42610 "tab" : function(e){
42611 this.onViewClick(false);
42612 this.fireEvent("specialkey", this, e);
42618 doRelay : function(foo, bar, hname){
42619 if(hname == 'down' || this.scope.isExpanded()){
42620 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
42627 this.queryDelay = Math.max(this.queryDelay || 10,
42628 this.mode == 'local' ? 10 : 250);
42629 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
42630 if(this.typeAhead){
42631 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
42633 if(this.editable !== false){
42634 this.el.on("keyup", this.onKeyUp, this);
42636 if(this.forceSelection){
42637 this.on('blur', this.doForce, this);
42641 onDestroy : function(){
42643 this.view.setStore(null);
42644 this.view.el.removeAllListeners();
42645 this.view.el.remove();
42646 this.view.purgeListeners();
42649 this.list.destroy();
42652 this.store.un('beforeload', this.onBeforeLoad, this);
42653 this.store.un('load', this.onLoad, this);
42654 this.store.un('loadexception', this.onLoadException, this);
42656 Roo.form.ComboBox.superclass.onDestroy.call(this);
42660 fireKey : function(e){
42661 if(e.isNavKeyPress() && !this.list.isVisible()){
42662 this.fireEvent("specialkey", this, e);
42667 onResize: function(w, h){
42668 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
42670 if(typeof w != 'number'){
42671 // we do not handle it!?!?
42674 var tw = this.trigger.getWidth();
42675 tw += this.addicon ? this.addicon.getWidth() : 0;
42676 tw += this.editicon ? this.editicon.getWidth() : 0;
42678 this.el.setWidth( this.adjustWidth('input', x));
42680 this.trigger.setStyle('left', x+'px');
42682 if(this.list && this.listWidth === undefined){
42683 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
42684 this.list.setWidth(lw);
42685 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42693 * Allow or prevent the user from directly editing the field text. If false is passed,
42694 * the user will only be able to select from the items defined in the dropdown list. This method
42695 * is the runtime equivalent of setting the 'editable' config option at config time.
42696 * @param {Boolean} value True to allow the user to directly edit the field text
42698 setEditable : function(value){
42699 if(value == this.editable){
42702 this.editable = value;
42704 this.el.dom.setAttribute('readOnly', true);
42705 this.el.on('mousedown', this.onTriggerClick, this);
42706 this.el.addClass('x-combo-noedit');
42708 this.el.dom.setAttribute('readOnly', false);
42709 this.el.un('mousedown', this.onTriggerClick, this);
42710 this.el.removeClass('x-combo-noedit');
42715 onBeforeLoad : function(){
42716 if(!this.hasFocus){
42719 this.innerList.update(this.loadingText ?
42720 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
42721 this.restrictHeight();
42722 this.selectedIndex = -1;
42726 onLoad : function(){
42727 if(!this.hasFocus){
42730 if(this.store.getCount() > 0){
42732 this.restrictHeight();
42733 if(this.lastQuery == this.allQuery){
42735 this.el.dom.select();
42737 if(!this.selectByValue(this.value, true)){
42738 this.select(0, true);
42742 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
42743 this.taTask.delay(this.typeAheadDelay);
42747 this.onEmptyResults();
42752 onLoadException : function()
42755 Roo.log(this.store.reader.jsonData);
42756 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
42757 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
42763 onTypeAhead : function(){
42764 if(this.store.getCount() > 0){
42765 var r = this.store.getAt(0);
42766 var newValue = r.data[this.displayField];
42767 var len = newValue.length;
42768 var selStart = this.getRawValue().length;
42769 if(selStart != len){
42770 this.setRawValue(newValue);
42771 this.selectText(selStart, newValue.length);
42777 onSelect : function(record, index){
42778 if(this.fireEvent('beforeselect', this, record, index) !== false){
42779 this.setFromData(index > -1 ? record.data : false);
42781 this.fireEvent('select', this, record, index);
42786 * Returns the currently selected field value or empty string if no value is set.
42787 * @return {String} value The selected value
42789 getValue : function(){
42790 if(this.valueField){
42791 return typeof this.value != 'undefined' ? this.value : '';
42793 return Roo.form.ComboBox.superclass.getValue.call(this);
42797 * Clears any text/value currently set in the field
42799 clearValue : function(){
42800 if(this.hiddenField){
42801 this.hiddenField.value = '';
42804 this.setRawValue('');
42805 this.lastSelectionText = '';
42810 * Sets the specified value into the field. If the value finds a match, the corresponding record text
42811 * will be displayed in the field. If the value does not match the data value of an existing item,
42812 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
42813 * Otherwise the field will be blank (although the value will still be set).
42814 * @param {String} value The value to match
42816 setValue : function(v){
42818 if(this.valueField){
42819 var r = this.findRecord(this.valueField, v);
42821 text = r.data[this.displayField];
42822 }else if(this.valueNotFoundText !== undefined){
42823 text = this.valueNotFoundText;
42826 this.lastSelectionText = text;
42827 if(this.hiddenField){
42828 this.hiddenField.value = v;
42830 Roo.form.ComboBox.superclass.setValue.call(this, text);
42834 * @property {Object} the last set data for the element
42839 * Sets the value of the field based on a object which is related to the record format for the store.
42840 * @param {Object} value the value to set as. or false on reset?
42842 setFromData : function(o){
42843 var dv = ''; // display value
42844 var vv = ''; // value value..
42846 if (this.displayField) {
42847 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
42849 // this is an error condition!!!
42850 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
42853 if(this.valueField){
42854 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
42856 if(this.hiddenField){
42857 this.hiddenField.value = vv;
42859 this.lastSelectionText = dv;
42860 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42864 // no hidden field.. - we store the value in 'value', but still display
42865 // display field!!!!
42866 this.lastSelectionText = dv;
42867 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42873 reset : function(){
42874 // overridden so that last data is reset..
42875 this.setValue(this.resetValue);
42876 this.originalValue = this.getValue();
42877 this.clearInvalid();
42878 this.lastData = false;
42880 this.view.clearSelections();
42884 findRecord : function(prop, value){
42886 if(this.store.getCount() > 0){
42887 this.store.each(function(r){
42888 if(r.data[prop] == value){
42898 getName: function()
42900 // returns hidden if it's set..
42901 if (!this.rendered) {return ''};
42902 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42906 onViewMove : function(e, t){
42907 this.inKeyMode = false;
42911 onViewOver : function(e, t){
42912 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42915 var item = this.view.findItemFromChild(t);
42917 var index = this.view.indexOf(item);
42918 this.select(index, false);
42923 onViewClick : function(doFocus)
42925 var index = this.view.getSelectedIndexes()[0];
42926 var r = this.store.getAt(index);
42928 this.onSelect(r, index);
42930 if(doFocus !== false && !this.blockFocus){
42936 restrictHeight : function(){
42937 this.innerList.dom.style.height = '';
42938 var inner = this.innerList.dom;
42939 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42940 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42941 this.list.beginUpdate();
42942 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42943 this.list.alignTo(this.el, this.listAlign);
42944 this.list.endUpdate();
42948 onEmptyResults : function(){
42953 * Returns true if the dropdown list is expanded, else false.
42955 isExpanded : function(){
42956 return this.list.isVisible();
42960 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42961 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42962 * @param {String} value The data value of the item to select
42963 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42964 * selected item if it is not currently in view (defaults to true)
42965 * @return {Boolean} True if the value matched an item in the list, else false
42967 selectByValue : function(v, scrollIntoView){
42968 if(v !== undefined && v !== null){
42969 var r = this.findRecord(this.valueField || this.displayField, v);
42971 this.select(this.store.indexOf(r), scrollIntoView);
42979 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42980 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42981 * @param {Number} index The zero-based index of the list item to select
42982 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42983 * selected item if it is not currently in view (defaults to true)
42985 select : function(index, scrollIntoView){
42986 this.selectedIndex = index;
42987 this.view.select(index);
42988 if(scrollIntoView !== false){
42989 var el = this.view.getNode(index);
42991 this.innerList.scrollChildIntoView(el, false);
42997 selectNext : function(){
42998 var ct = this.store.getCount();
43000 if(this.selectedIndex == -1){
43002 }else if(this.selectedIndex < ct-1){
43003 this.select(this.selectedIndex+1);
43009 selectPrev : function(){
43010 var ct = this.store.getCount();
43012 if(this.selectedIndex == -1){
43014 }else if(this.selectedIndex != 0){
43015 this.select(this.selectedIndex-1);
43021 onKeyUp : function(e){
43022 if(this.editable !== false && !e.isSpecialKey()){
43023 this.lastKey = e.getKey();
43024 this.dqTask.delay(this.queryDelay);
43029 validateBlur : function(){
43030 return !this.list || !this.list.isVisible();
43034 initQuery : function(){
43035 this.doQuery(this.getRawValue());
43039 doForce : function(){
43040 if(this.el.dom.value.length > 0){
43041 this.el.dom.value =
43042 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
43048 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
43049 * query allowing the query action to be canceled if needed.
43050 * @param {String} query The SQL query to execute
43051 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
43052 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
43053 * saved in the current store (defaults to false)
43055 doQuery : function(q, forceAll){
43056 if(q === undefined || q === null){
43061 forceAll: forceAll,
43065 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
43069 forceAll = qe.forceAll;
43070 if(forceAll === true || (q.length >= this.minChars)){
43071 if(this.lastQuery != q || this.alwaysQuery){
43072 this.lastQuery = q;
43073 if(this.mode == 'local'){
43074 this.selectedIndex = -1;
43076 this.store.clearFilter();
43078 this.store.filter(this.displayField, q);
43082 this.store.baseParams[this.queryParam] = q;
43084 params: this.getParams(q)
43089 this.selectedIndex = -1;
43096 getParams : function(q){
43098 //p[this.queryParam] = q;
43101 p.limit = this.pageSize;
43107 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
43109 collapse : function(){
43110 if(!this.isExpanded()){
43114 Roo.get(document).un('mousedown', this.collapseIf, this);
43115 Roo.get(document).un('mousewheel', this.collapseIf, this);
43116 if (!this.editable) {
43117 Roo.get(document).un('keydown', this.listKeyPress, this);
43119 this.fireEvent('collapse', this);
43123 collapseIf : function(e){
43124 if(!e.within(this.wrap) && !e.within(this.list)){
43130 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
43132 expand : function(){
43133 if(this.isExpanded() || !this.hasFocus){
43136 this.list.alignTo(this.el, this.listAlign);
43138 Roo.get(document).on('mousedown', this.collapseIf, this);
43139 Roo.get(document).on('mousewheel', this.collapseIf, this);
43140 if (!this.editable) {
43141 Roo.get(document).on('keydown', this.listKeyPress, this);
43144 this.fireEvent('expand', this);
43148 // Implements the default empty TriggerField.onTriggerClick function
43149 onTriggerClick : function(){
43153 if(this.isExpanded()){
43155 if (!this.blockFocus) {
43160 this.hasFocus = true;
43161 if(this.triggerAction == 'all') {
43162 this.doQuery(this.allQuery, true);
43164 this.doQuery(this.getRawValue());
43166 if (!this.blockFocus) {
43171 listKeyPress : function(e)
43173 //Roo.log('listkeypress');
43174 // scroll to first matching element based on key pres..
43175 if (e.isSpecialKey()) {
43178 var k = String.fromCharCode(e.getKey()).toUpperCase();
43181 var csel = this.view.getSelectedNodes();
43182 var cselitem = false;
43184 var ix = this.view.indexOf(csel[0]);
43185 cselitem = this.store.getAt(ix);
43186 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
43192 this.store.each(function(v) {
43194 // start at existing selection.
43195 if (cselitem.id == v.id) {
43201 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
43202 match = this.store.indexOf(v);
43207 if (match === false) {
43208 return true; // no more action?
43211 this.view.select(match);
43212 var sn = Roo.get(this.view.getSelectedNodes()[0]);
43213 sn.scrollIntoView(sn.dom.parentNode, false);
43217 * @cfg {Boolean} grow
43221 * @cfg {Number} growMin
43225 * @cfg {Number} growMax
43233 * Copyright(c) 2010-2012, Roo J Solutions Limited
43240 * @class Roo.form.ComboBoxArray
43241 * @extends Roo.form.TextField
43242 * A facebook style adder... for lists of email / people / countries etc...
43243 * pick multiple items from a combo box, and shows each one.
43245 * Fred [x] Brian [x] [Pick another |v]
43248 * For this to work: it needs various extra information
43249 * - normal combo problay has
43251 * + displayField, valueField
43253 * For our purpose...
43256 * If we change from 'extends' to wrapping...
43263 * Create a new ComboBoxArray.
43264 * @param {Object} config Configuration options
43268 Roo.form.ComboBoxArray = function(config)
43272 * @event beforeremove
43273 * Fires before remove the value from the list
43274 * @param {Roo.form.ComboBoxArray} _self This combo box array
43275 * @param {Roo.form.ComboBoxArray.Item} item removed item
43277 'beforeremove' : true,
43280 * Fires when remove the value from the list
43281 * @param {Roo.form.ComboBoxArray} _self This combo box array
43282 * @param {Roo.form.ComboBoxArray.Item} item removed item
43289 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
43291 this.items = new Roo.util.MixedCollection(false);
43293 // construct the child combo...
43303 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
43306 * @cfg {Roo.form.ComboBox} combo [required] The combo box that is wrapped
43311 // behavies liek a hiddne field
43312 inputType: 'hidden',
43314 * @cfg {Number} width The width of the box that displays the selected element
43321 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
43325 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
43327 hiddenName : false,
43329 * @cfg {String} seperator The value seperator normally ','
43333 // private the array of items that are displayed..
43335 // private - the hidden field el.
43337 // private - the filed el..
43340 //validateValue : function() { return true; }, // all values are ok!
43341 //onAddClick: function() { },
43343 onRender : function(ct, position)
43346 // create the standard hidden element
43347 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
43350 // give fake names to child combo;
43351 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
43352 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
43354 this.combo = Roo.factory(this.combo, Roo.form);
43355 this.combo.onRender(ct, position);
43356 if (typeof(this.combo.width) != 'undefined') {
43357 this.combo.onResize(this.combo.width,0);
43360 this.combo.initEvents();
43362 // assigned so form know we need to do this..
43363 this.store = this.combo.store;
43364 this.valueField = this.combo.valueField;
43365 this.displayField = this.combo.displayField ;
43368 this.combo.wrap.addClass('x-cbarray-grp');
43370 var cbwrap = this.combo.wrap.createChild(
43371 {tag: 'div', cls: 'x-cbarray-cb'},
43376 this.hiddenEl = this.combo.wrap.createChild({
43377 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
43379 this.el = this.combo.wrap.createChild({
43380 tag: 'input', type:'hidden' , name: this.name, value : ''
43382 // this.el.dom.removeAttribute("name");
43385 this.outerWrap = this.combo.wrap;
43386 this.wrap = cbwrap;
43388 this.outerWrap.setWidth(this.width);
43389 this.outerWrap.dom.removeChild(this.el.dom);
43391 this.wrap.dom.appendChild(this.el.dom);
43392 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
43393 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
43395 this.combo.trigger.setStyle('position','relative');
43396 this.combo.trigger.setStyle('left', '0px');
43397 this.combo.trigger.setStyle('top', '2px');
43399 this.combo.el.setStyle('vertical-align', 'text-bottom');
43401 //this.trigger.setStyle('vertical-align', 'top');
43403 // this should use the code from combo really... on('add' ....)
43407 this.adder = this.outerWrap.createChild(
43408 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
43410 this.adder.on('click', function(e) {
43411 _t.fireEvent('adderclick', this, e);
43415 //this.adder.on('click', this.onAddClick, _t);
43418 this.combo.on('select', function(cb, rec, ix) {
43419 this.addItem(rec.data);
43422 cb.el.dom.value = '';
43423 //cb.lastData = rec.data;
43432 getName: function()
43434 // returns hidden if it's set..
43435 if (!this.rendered) {return ''};
43436 return this.hiddenName ? this.hiddenName : this.name;
43441 onResize: function(w, h){
43444 // not sure if this is needed..
43445 //this.combo.onResize(w,h);
43447 if(typeof w != 'number'){
43448 // we do not handle it!?!?
43451 var tw = this.combo.trigger.getWidth();
43452 tw += this.addicon ? this.addicon.getWidth() : 0;
43453 tw += this.editicon ? this.editicon.getWidth() : 0;
43455 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
43457 this.combo.trigger.setStyle('left', '0px');
43459 if(this.list && this.listWidth === undefined){
43460 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
43461 this.list.setWidth(lw);
43462 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
43469 addItem: function(rec)
43471 var valueField = this.combo.valueField;
43472 var displayField = this.combo.displayField;
43474 if (this.items.indexOfKey(rec[valueField]) > -1) {
43475 //console.log("GOT " + rec.data.id);
43479 var x = new Roo.form.ComboBoxArray.Item({
43480 //id : rec[this.idField],
43482 displayField : displayField ,
43483 tipField : displayField ,
43487 this.items.add(rec[valueField],x);
43488 // add it before the element..
43489 this.updateHiddenEl();
43490 x.render(this.outerWrap, this.wrap.dom);
43491 // add the image handler..
43494 updateHiddenEl : function()
43497 if (!this.hiddenEl) {
43501 var idField = this.combo.valueField;
43503 this.items.each(function(f) {
43504 ar.push(f.data[idField]);
43506 this.hiddenEl.dom.value = ar.join(this.seperator);
43512 this.items.clear();
43514 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
43518 this.el.dom.value = '';
43519 if (this.hiddenEl) {
43520 this.hiddenEl.dom.value = '';
43524 getValue: function()
43526 return this.hiddenEl ? this.hiddenEl.dom.value : '';
43528 setValue: function(v) // not a valid action - must use addItems..
43533 if (this.store.isLocal && (typeof(v) == 'string')) {
43534 // then we can use the store to find the values..
43535 // comma seperated at present.. this needs to allow JSON based encoding..
43536 this.hiddenEl.value = v;
43538 Roo.each(v.split(this.seperator), function(k) {
43539 Roo.log("CHECK " + this.valueField + ',' + k);
43540 var li = this.store.query(this.valueField, k);
43545 add[this.valueField] = k;
43546 add[this.displayField] = li.item(0).data[this.displayField];
43552 if (typeof(v) == 'object' ) {
43553 // then let's assume it's an array of objects..
43554 Roo.each(v, function(l) {
43556 if (typeof(l) == 'string') {
43558 add[this.valueField] = l;
43559 add[this.displayField] = l
43568 setFromData: function(v)
43570 // this recieves an object, if setValues is called.
43572 this.el.dom.value = v[this.displayField];
43573 this.hiddenEl.dom.value = v[this.valueField];
43574 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
43577 var kv = v[this.valueField];
43578 var dv = v[this.displayField];
43579 kv = typeof(kv) != 'string' ? '' : kv;
43580 dv = typeof(dv) != 'string' ? '' : dv;
43583 var keys = kv.split(this.seperator);
43584 var display = dv.split(this.seperator);
43585 for (var i = 0 ; i < keys.length; i++) {
43587 add[this.valueField] = keys[i];
43588 add[this.displayField] = display[i];
43596 * Validates the combox array value
43597 * @return {Boolean} True if the value is valid, else false
43599 validate : function(){
43600 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
43601 this.clearInvalid();
43607 validateValue : function(value){
43608 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
43616 isDirty : function() {
43617 if(this.disabled) {
43622 var d = Roo.decode(String(this.originalValue));
43624 return String(this.getValue()) !== String(this.originalValue);
43627 var originalValue = [];
43629 for (var i = 0; i < d.length; i++){
43630 originalValue.push(d[i][this.valueField]);
43633 return String(this.getValue()) !== String(originalValue.join(this.seperator));
43642 * @class Roo.form.ComboBoxArray.Item
43643 * @extends Roo.BoxComponent
43644 * A selected item in the list
43645 * Fred [x] Brian [x] [Pick another |v]
43648 * Create a new item.
43649 * @param {Object} config Configuration options
43652 Roo.form.ComboBoxArray.Item = function(config) {
43653 config.id = Roo.id();
43654 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
43657 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
43660 displayField : false,
43664 defaultAutoCreate : {
43666 cls: 'x-cbarray-item',
43673 src : Roo.BLANK_IMAGE_URL ,
43681 onRender : function(ct, position)
43683 Roo.form.Field.superclass.onRender.call(this, ct, position);
43686 var cfg = this.getAutoCreate();
43687 this.el = ct.createChild(cfg, position);
43690 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
43692 this.el.child('div').dom.innerHTML = this.cb.renderer ?
43693 this.cb.renderer(this.data) :
43694 String.format('{0}',this.data[this.displayField]);
43697 this.el.child('div').dom.setAttribute('qtip',
43698 String.format('{0}',this.data[this.tipField])
43701 this.el.child('img').on('click', this.remove, this);
43705 remove : function()
43707 if(this.cb.disabled){
43711 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
43712 this.cb.items.remove(this);
43713 this.el.child('img').un('click', this.remove, this);
43715 this.cb.updateHiddenEl();
43717 this.cb.fireEvent('remove', this.cb, this);
43722 * RooJS Library 1.1.1
43723 * Copyright(c) 2008-2011 Alan Knowles
43730 * @class Roo.form.ComboNested
43731 * @extends Roo.form.ComboBox
43732 * A combobox for that allows selection of nested items in a list,
43747 * Create a new ComboNested
43748 * @param {Object} config Configuration options
43750 Roo.form.ComboNested = function(config){
43751 Roo.form.ComboCheck.superclass.constructor.call(this, config);
43752 // should verify some data...
43754 // hiddenName = required..
43755 // displayField = required
43756 // valudField == required
43757 var req= [ 'hiddenName', 'displayField', 'valueField' ];
43759 Roo.each(req, function(e) {
43760 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
43761 throw "Roo.form.ComboNested : missing value for: " + e;
43768 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
43771 * @config {Number} max Number of columns to show
43776 list : null, // the outermost div..
43777 innerLists : null, // the
43781 loadingChildren : false,
43783 onRender : function(ct, position)
43785 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
43787 if(this.hiddenName){
43788 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
43790 this.hiddenField.value =
43791 this.hiddenValue !== undefined ? this.hiddenValue :
43792 this.value !== undefined ? this.value : '';
43794 // prevent input submission
43795 this.el.dom.removeAttribute('name');
43801 this.el.dom.setAttribute('autocomplete', 'off');
43804 var cls = 'x-combo-list';
43806 this.list = new Roo.Layer({
43807 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
43810 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
43811 this.list.setWidth(lw);
43812 this.list.swallowEvent('mousewheel');
43813 this.assetHeight = 0;
43816 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
43817 this.assetHeight += this.header.getHeight();
43819 this.innerLists = [];
43822 for (var i =0 ; i < this.maxColumns; i++) {
43823 this.onRenderList( cls, i);
43826 // always needs footer, as we are going to have an 'OK' button.
43827 this.footer = this.list.createChild({cls:cls+'-ft'});
43828 this.pageTb = new Roo.Toolbar(this.footer);
43833 handler: function()
43839 if ( this.allowBlank && !this.disableClear) {
43841 this.pageTb.add(new Roo.Toolbar.Fill(), {
43842 cls: 'x-btn-icon x-btn-clear',
43844 handler: function()
43847 _this.clearValue();
43848 _this.onSelect(false, -1);
43853 this.assetHeight += this.footer.getHeight();
43857 onRenderList : function ( cls, i)
43860 var lw = Math.floor(
43861 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43864 this.list.setWidth(lw); // default to '1'
43866 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
43867 //il.on('mouseover', this.onViewOver, this, { list: i });
43868 //il.on('mousemove', this.onViewMove, this, { list: i });
43870 il.setStyle({ 'overflow-x' : 'hidden'});
43873 this.tpl = new Roo.Template({
43874 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
43875 isEmpty: function (value, allValues) {
43877 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
43878 return dl ? 'has-children' : 'no-children'
43883 var store = this.store;
43885 store = new Roo.data.SimpleStore({
43886 //fields : this.store.reader.meta.fields,
43887 reader : this.store.reader,
43891 this.stores[i] = store;
43893 var view = this.views[i] = new Roo.View(
43899 selectedClass: this.selectedClass
43902 view.getEl().setWidth(lw);
43903 view.getEl().setStyle({
43904 position: i < 1 ? 'relative' : 'absolute',
43906 left: (i * lw ) + 'px',
43907 display : i > 0 ? 'none' : 'block'
43909 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
43910 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
43911 //view.on('click', this.onViewClick, this, { list : i });
43913 store.on('beforeload', this.onBeforeLoad, this);
43914 store.on('load', this.onLoad, this, { list : i});
43915 store.on('loadexception', this.onLoadException, this);
43917 // hide the other vies..
43923 restrictHeight : function()
43926 Roo.each(this.innerLists, function(il,i) {
43927 var el = this.views[i].getEl();
43928 el.dom.style.height = '';
43929 var inner = el.dom;
43930 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
43931 // only adjust heights on other ones..
43932 mh = Math.max(h, mh);
43935 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43936 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43943 this.list.beginUpdate();
43944 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43945 this.list.alignTo(this.el, this.listAlign);
43946 this.list.endUpdate();
43951 // -- store handlers..
43953 onBeforeLoad : function()
43955 if(!this.hasFocus){
43958 this.innerLists[0].update(this.loadingText ?
43959 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43960 this.restrictHeight();
43961 this.selectedIndex = -1;
43964 onLoad : function(a,b,c,d)
43966 if (!this.loadingChildren) {
43967 // then we are loading the top level. - hide the children
43968 for (var i = 1;i < this.views.length; i++) {
43969 this.views[i].getEl().setStyle({ display : 'none' });
43971 var lw = Math.floor(
43972 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43975 this.list.setWidth(lw); // default to '1'
43979 if(!this.hasFocus){
43983 if(this.store.getCount() > 0) {
43985 this.restrictHeight();
43987 this.onEmptyResults();
43990 if (!this.loadingChildren) {
43991 this.selectActive();
43994 this.stores[1].loadData([]);
43995 this.stores[2].loadData([]);
44004 onLoadException : function()
44007 Roo.log(this.store.reader.jsonData);
44008 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
44009 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
44014 // no cleaning of leading spaces on blur here.
44015 cleanLeadingSpace : function(e) { },
44018 onSelectChange : function (view, sels, opts )
44020 var ix = view.getSelectedIndexes();
44022 if (opts.list > this.maxColumns - 2) {
44023 if (view.store.getCount()< 1) {
44024 this.views[opts.list ].getEl().setStyle({ display : 'none' });
44028 // used to clear ?? but if we are loading unselected
44029 this.setFromData(view.store.getAt(ix[0]).data);
44038 // this get's fired when trigger opens..
44039 // this.setFromData({});
44040 var str = this.stores[opts.list+1];
44041 str.data.clear(); // removeall wihtout the fire events..
44045 var rec = view.store.getAt(ix[0]);
44047 this.setFromData(rec.data);
44048 this.fireEvent('select', this, rec, ix[0]);
44050 var lw = Math.floor(
44052 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
44053 ) / this.maxColumns
44055 this.loadingChildren = true;
44056 this.stores[opts.list+1].loadDataFromChildren( rec );
44057 this.loadingChildren = false;
44058 var dl = this.stores[opts.list+1]. getTotalCount();
44060 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
44062 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
44063 for (var i = opts.list+2; i < this.views.length;i++) {
44064 this.views[i].getEl().setStyle({ display : 'none' });
44067 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
44068 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
44070 if (this.isLoading) {
44071 // this.selectActive(opts.list);
44079 onDoubleClick : function()
44081 this.collapse(); //??
44089 recordToStack : function(store, prop, value, stack)
44091 var cstore = new Roo.data.SimpleStore({
44092 //fields : this.store.reader.meta.fields, // we need array reader.. for
44093 reader : this.store.reader,
44097 var record = false;
44099 if(store.getCount() < 1){
44102 store.each(function(r){
44103 if(r.data[prop] == value){
44108 if (r.data.cn && r.data.cn.length) {
44109 cstore.loadDataFromChildren( r);
44110 var cret = _this.recordToStack(cstore, prop, value, stack);
44111 if (cret !== false) {
44120 if (record == false) {
44123 stack.unshift(srec);
44128 * find the stack of stores that match our value.
44133 selectActive : function ()
44135 // if store is not loaded, then we will need to wait for that to happen first.
44137 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
44138 for (var i = 0; i < stack.length; i++ ) {
44139 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
44151 * Ext JS Library 1.1.1
44152 * Copyright(c) 2006-2007, Ext JS, LLC.
44154 * Originally Released Under LGPL - original licence link has changed is not relivant.
44157 * <script type="text/javascript">
44160 * @class Roo.form.Checkbox
44161 * @extends Roo.form.Field
44162 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
44164 * Creates a new Checkbox
44165 * @param {Object} config Configuration options
44167 Roo.form.Checkbox = function(config){
44168 Roo.form.Checkbox.superclass.constructor.call(this, config);
44172 * Fires when the checkbox is checked or unchecked.
44173 * @param {Roo.form.Checkbox} this This checkbox
44174 * @param {Boolean} checked The new checked value
44180 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
44182 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
44184 focusClass : undefined,
44186 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
44188 fieldClass: "x-form-field",
44190 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
44194 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44195 * {tag: "input", type: "checkbox", autocomplete: "off"})
44197 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
44199 * @cfg {String} boxLabel The text that appears beside the checkbox
44203 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
44207 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
44209 valueOff: '0', // value when not checked..
44211 actionMode : 'viewEl',
44214 itemCls : 'x-menu-check-item x-form-item',
44215 groupClass : 'x-menu-group-item',
44216 inputType : 'hidden',
44219 inSetChecked: false, // check that we are not calling self...
44221 inputElement: false, // real input element?
44222 basedOn: false, // ????
44224 isFormField: true, // not sure where this is needed!!!!
44226 onResize : function(){
44227 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
44228 if(!this.boxLabel){
44229 this.el.alignTo(this.wrap, 'c-c');
44233 initEvents : function(){
44234 Roo.form.Checkbox.superclass.initEvents.call(this);
44235 this.el.on("click", this.onClick, this);
44236 this.el.on("change", this.onClick, this);
44240 getResizeEl : function(){
44244 getPositionEl : function(){
44249 onRender : function(ct, position){
44250 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
44252 if(this.inputValue !== undefined){
44253 this.el.dom.value = this.inputValue;
44256 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
44257 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
44258 var viewEl = this.wrap.createChild({
44259 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
44260 this.viewEl = viewEl;
44261 this.wrap.on('click', this.onClick, this);
44263 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
44264 this.el.on('propertychange', this.setFromHidden, this); //ie
44269 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
44270 // viewEl.on('click', this.onClick, this);
44272 //if(this.checked){
44273 this.setChecked(this.checked);
44275 //this.checked = this.el.dom;
44281 initValue : Roo.emptyFn,
44284 * Returns the checked state of the checkbox.
44285 * @return {Boolean} True if checked, else false
44287 getValue : function(){
44289 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
44291 return this.valueOff;
44296 onClick : function(){
44297 if (this.disabled) {
44300 this.setChecked(!this.checked);
44302 //if(this.el.dom.checked != this.checked){
44303 // this.setValue(this.el.dom.checked);
44308 * Sets the checked state of the checkbox.
44309 * On is always based on a string comparison between inputValue and the param.
44310 * @param {Boolean/String} value - the value to set
44311 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
44313 setValue : function(v,suppressEvent){
44316 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
44317 //if(this.el && this.el.dom){
44318 // this.el.dom.checked = this.checked;
44319 // this.el.dom.defaultChecked = this.checked;
44321 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
44322 //this.fireEvent("check", this, this.checked);
44325 setChecked : function(state,suppressEvent)
44327 if (this.inSetChecked) {
44328 this.checked = state;
44334 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
44336 this.checked = state;
44337 if(suppressEvent !== true){
44338 this.fireEvent('check', this, state);
44340 this.inSetChecked = true;
44341 this.el.dom.value = state ? this.inputValue : this.valueOff;
44342 this.inSetChecked = false;
44345 // handle setting of hidden value by some other method!!?!?
44346 setFromHidden: function()
44351 //console.log("SET FROM HIDDEN");
44352 //alert('setFrom hidden');
44353 this.setValue(this.el.dom.value);
44356 onDestroy : function()
44359 Roo.get(this.viewEl).remove();
44362 Roo.form.Checkbox.superclass.onDestroy.call(this);
44365 setBoxLabel : function(str)
44367 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
44372 * Ext JS Library 1.1.1
44373 * Copyright(c) 2006-2007, Ext JS, LLC.
44375 * Originally Released Under LGPL - original licence link has changed is not relivant.
44378 * <script type="text/javascript">
44382 * @class Roo.form.Radio
44383 * @extends Roo.form.Checkbox
44384 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
44385 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
44387 * Creates a new Radio
44388 * @param {Object} config Configuration options
44390 Roo.form.Radio = function(){
44391 Roo.form.Radio.superclass.constructor.apply(this, arguments);
44393 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
44394 inputType: 'radio',
44397 * If this radio is part of a group, it will return the selected value
44400 getGroupValue : function(){
44401 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
44405 onRender : function(ct, position){
44406 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
44408 if(this.inputValue !== undefined){
44409 this.el.dom.value = this.inputValue;
44412 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
44413 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
44414 //var viewEl = this.wrap.createChild({
44415 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
44416 //this.viewEl = viewEl;
44417 //this.wrap.on('click', this.onClick, this);
44419 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
44420 //this.el.on('propertychange', this.setFromHidden, this); //ie
44425 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
44426 // viewEl.on('click', this.onClick, this);
44429 this.el.dom.checked = 'checked' ;
44435 });Roo.htmleditor = {};
44437 * @class Roo.htmleditor.Filter
44438 * Base Class for filtering htmleditor stuff. - do not use this directly - extend it.
44439 * @cfg {DomElement} node The node to iterate and filter
44440 * @cfg {boolean|String|Array} tag Tags to replace
44442 * Create a new Filter.
44443 * @param {Object} config Configuration options
44448 Roo.htmleditor.Filter = function(cfg) {
44449 Roo.apply(this.cfg);
44450 // this does not actually call walk as it's really just a abstract class
44454 Roo.htmleditor.Filter.prototype = {
44460 // overrride to do replace comments.
44461 replaceComment : false,
44463 // overrride to do replace or do stuff with tags..
44464 replaceTag : false,
44466 walk : function(dom)
44468 Roo.each( Array.from(dom.childNodes), function( e ) {
44471 case e.nodeType == 8 && typeof(this.replaceComment) != 'undefined': // comment
44472 this.replaceComment(e);
44475 case e.nodeType != 1: //not a node.
44478 case this.tag === true: // everything
44479 case typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1: // array and it matches.
44480 case typeof(this.tag) == 'string' && this.tag == e.tagName: // array and it matches.
44481 if (this.replaceTag && false === this.replaceTag(e)) {
44484 if (e.hasChildNodes()) {
44489 default: // tags .. that do not match.
44490 if (e.hasChildNodes()) {
44501 * @class Roo.htmleditor.FilterAttributes
44502 * clean attributes and styles including http:// etc.. in attribute
44504 * Run a new Attribute Filter
44505 * @param {Object} config Configuration options
44507 Roo.htmleditor.FilterAttributes = function(cfg)
44509 Roo.apply(this, cfg);
44510 this.attrib_black = this.attrib_black || [];
44511 this.attrib_clean = this.attrib_clean || [];
44512 this.style_white = this.style_white || [];
44513 this.style_black = this.style_black || [];
44514 this.walk(cfg.node);
44517 Roo.extend(Roo.htmleditor.FilterAttributes, Roo.htmleditor.Filter,
44519 tag: true, // all tags
44521 attrib_black : false, // array
44522 attrib_clean : false,
44523 style_white : false,
44524 style_black : false,
44527 replaceTag : function(node)
44529 if (!node.attributes || !node.attributes.length) {
44533 for (var i = node.attributes.length-1; i > -1 ; i--) {
44534 var a = node.attributes[i];
44537 if (a.name.toLowerCase().substr(0,2)=='on') {
44538 node.removeAttribute(a.name);
44543 if (this.attrib_black.indexOf(a.name.toLowerCase()) > -1) {
44544 node.removeAttribute(a.name);
44547 if (this.attrib_clean.indexOf(a.name.toLowerCase()) > -1) {
44548 this.cleanAttr(node,a.name,a.value); // fixme..
44551 if (a.name == 'style') {
44552 this.cleanStyle(node,a.name,a.value);
44555 /// clean up MS crap..
44556 // tecnically this should be a list of valid class'es..
44559 if (a.name == 'class') {
44560 if (a.value.match(/^Mso/)) {
44561 node.removeAttribute('class');
44564 if (a.value.match(/^body$/)) {
44565 node.removeAttribute('class');
44575 return true; // clean children
44578 cleanAttr: function(node, n,v)
44581 if (v.match(/^\./) || v.match(/^\//)) {
44584 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44587 if (v.match(/^#/)) {
44590 if (v.match(/^\{/)) { // allow template editing.
44593 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44594 node.removeAttribute(n);
44597 cleanStyle : function(node, n,v)
44599 if (v.match(/expression/)) { //XSS?? should we even bother..
44600 node.removeAttribute(n);
44604 var parts = v.split(/;/);
44607 Roo.each(parts, function(p) {
44608 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44612 var l = p.split(':').shift().replace(/\s+/g,'');
44613 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44615 if ( this.style_black.length && (this.style_black.indexOf(l) > -1 || this.style_black.indexOf(l.toLowerCase()) > -1)) {
44619 // only allow 'c whitelisted system attributes'
44620 if ( this.style_white.length && style_white.indexOf(l) < 0 && style_white.indexOf(l.toLowerCase()) < 0 ) {
44628 if (clean.length) {
44629 node.setAttribute(n, clean.join(';'));
44631 node.removeAttribute(n);
44640 * @class Roo.htmleditor.FilterBlack
44641 * remove blacklisted elements.
44643 * Run a new Blacklisted Filter
44644 * @param {Object} config Configuration options
44647 Roo.htmleditor.FilterBlack = function(cfg)
44649 Roo.apply(this, cfg);
44650 this.walk(cfg.node);
44653 Roo.extend(Roo.htmleditor.FilterBlack, Roo.htmleditor.Filter,
44655 tag : true, // all elements.
44657 replace : function(n)
44659 n.parentNode.removeChild(n);
44663 * @class Roo.htmleditor.FilterComment
44666 * Run a new Comments Filter
44667 * @param {Object} config Configuration options
44669 Roo.htmleditor.FilterComment = function(cfg)
44671 this.walk(cfg.node);
44674 Roo.extend(Roo.htmleditor.FilterComment, Roo.htmleditor.Filter,
44677 replaceComment : function(n)
44679 n.parentNode.removeChild(n);
44682 * @class Roo.htmleditor.FilterKeepChildren
44683 * remove tags but keep children
44685 * Run a new Keep Children Filter
44686 * @param {Object} config Configuration options
44689 Roo.htmleditor.FilterKeepChildren = function(cfg)
44691 Roo.apply(this, cfg);
44692 this.walk(cfg.node);
44695 Roo.extend(Roo.htmleditor.FilterKeepChildren, Roo.htmleditor.FilterBlack,
44699 replaceTag : function(node)
44701 // walk children...
44702 var ar = Array.from(node.childNodes);
44703 for (var i = 0; i < ar.length; i++) {
44704 node.removeChild(ar[i]);
44705 // what if we need to walk these???
44706 node.parentNode.insertBefore(ar[i], node);
44709 node.parentNode.removeChild(node);
44710 return false; // don't walk children
44715 * @class Roo.htmleditor.FilterParagraph
44716 * paragraphs cause a nightmare for shared content - this filter is designed to be called ? at various points when editing
44717 * like on 'push' to remove the <p> tags and replace them with line breaks.
44719 * Run a new Paragraph Filter
44720 * @param {Object} config Configuration options
44723 Roo.htmleditor.FilterParagraph = function(cfg)
44725 // no need to apply config.
44726 this.walk(cfg.node);
44729 Roo.extend(Roo.htmleditor.FilterParagraph, Roo.htmleditor.Filter,
44736 replaceTag : function(node)
44739 if (node.childNodes.length == 1 &&
44740 node.childNodes[0].nodeType == 3 &&
44741 node.childNodes[0].textContent.trim().length < 1
44743 // remove and replace with '<BR>';
44744 node.parentNode.replaceChild(node.ownerDocument.createElement('BR'),node);
44745 return false; // no need to walk..
44747 var ar = Array.from(node.childNodes);
44748 for (var i = 0; i < ar.length; i++) {
44749 node.removeChild(ar[i]);
44750 // what if we need to walk these???
44751 node.parentNode.insertBefore(ar[i], node);
44753 // now what about this?
44757 node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
44758 node.parentNode.removeChild(node);
44765 * @class Roo.htmleditor.FilterSpan
44766 * filter span's with no attributes out..
44768 * Run a new Span Filter
44769 * @param {Object} config Configuration options
44772 Roo.htmleditor.FilterSpan = function(cfg)
44774 // no need to apply config.
44775 this.walk(cfg.node);
44778 Roo.extend(Roo.htmleditor.FilterSpan, Roo.htmleditor.FilterKeepChildren,
44784 replaceTag : function(node)
44786 if (node.attributes && node.attributes.length > 0) {
44787 return true; // walk if there are any.
44789 Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this, node);
44795 * @class Roo.htmleditor.FilterTableWidth
44796 try and remove table width data - as that frequently messes up other stuff.
44798 * was cleanTableWidths.
44800 * Quite often pasting from word etc.. results in tables with column and widths.
44801 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44804 * Run a new Table Filter
44805 * @param {Object} config Configuration options
44808 Roo.htmleditor.FilterTableWidth = function(cfg)
44810 // no need to apply config.
44811 this.tag = ['TABLE', 'TD', 'TR', 'TH', 'THEAD', 'TBODY' ];
44812 this.walk(cfg.node);
44815 Roo.extend(Roo.htmleditor.FilterTableWidth, Roo.htmleditor.Filter,
44820 replaceTag: function(node) {
44824 if (node.hasAttribute('width')) {
44825 node.removeAttribute('width');
44829 if (node.hasAttribute("style")) {
44832 var styles = node.getAttribute("style").split(";");
44834 Roo.each(styles, function(s) {
44835 if (!s.match(/:/)) {
44838 var kv = s.split(":");
44839 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44842 // what ever is left... we allow.
44845 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44846 if (!nstyle.length) {
44847 node.removeAttribute('style');
44851 return true; // continue doing children..
44854 * @class Roo.htmleditor.FilterWord
44855 * try and clean up all the mess that Word generates.
44857 * This is the 'nice version' - see 'Heavy' that white lists a very short list of elements, and multi-filters
44860 * Run a new Span Filter
44861 * @param {Object} config Configuration options
44864 Roo.htmleditor.FilterWord = function(cfg)
44866 // no need to apply config.
44867 this.walk(cfg.node);
44870 Roo.extend(Roo.htmleditor.FilterWord, Roo.htmleditor.Filter,
44876 * Clean up MS wordisms...
44878 replaceTag : function(node)
44881 // no idea what this does - span with text, replaceds with just text.
44883 node.nodeName == 'SPAN' &&
44884 !node.hasAttributes() &&
44885 node.childNodes.length == 1 &&
44886 node.firstChild.nodeName == "#text"
44888 var textNode = node.firstChild;
44889 node.removeChild(textNode);
44890 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44891 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44893 node.parentNode.insertBefore(textNode, node);
44894 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44895 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44898 node.parentNode.removeChild(node);
44899 return false; // dont do chidren - we have remove our node - so no need to do chdhilren?
44904 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44905 node.parentNode.removeChild(node);
44906 return false; // dont do chidlren
44908 //Roo.log(node.tagName);
44909 // remove - but keep children..
44910 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44911 //Roo.log('-- removed');
44912 while (node.childNodes.length) {
44913 var cn = node.childNodes[0];
44914 node.removeChild(cn);
44915 node.parentNode.insertBefore(cn, node);
44916 // move node to parent - and clean it..
44917 this.replaceTag(cn);
44919 node.parentNode.removeChild(node);
44920 /// no need to iterate chidlren = it's got none..
44921 //this.iterateChildren(node, this.cleanWord);
44922 return false; // no need to iterate children.
44925 if (node.className.length) {
44927 var cn = node.className.split(/\W+/);
44929 Roo.each(cn, function(cls) {
44930 if (cls.match(/Mso[a-zA-Z]+/)) {
44935 node.className = cna.length ? cna.join(' ') : '';
44937 node.removeAttribute("class");
44941 if (node.hasAttribute("lang")) {
44942 node.removeAttribute("lang");
44945 if (node.hasAttribute("style")) {
44947 var styles = node.getAttribute("style").split(";");
44949 Roo.each(styles, function(s) {
44950 if (!s.match(/:/)) {
44953 var kv = s.split(":");
44954 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44957 // what ever is left... we allow.
44960 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44961 if (!nstyle.length) {
44962 node.removeAttribute('style');
44965 return true; // do children
44972 * @class Roo.htmleditor.Tidy
44974 * @cfg {Roo.HtmlEditorCore} core the editor.
44976 * Create a new Filter.
44977 * @param {Object} config Configuration options
44981 Roo.htmleditor.Tidy = function(cfg) {
44982 Roo.apply(this, cfg);
44984 this.core.doc.body.innerHTML = this.tidy(this.core.doc.body, '');
44988 Roo.htmleditor.Tidy.toString = function(node)
44990 return Roo.htmleditor.Tidy.prototype.tidy(node, '');
44993 Roo.htmleditor.Tidy.prototype = {
44996 wrap : function(s) {
44997 return s.replace(/\n/g, " ").replace(/(?![^\n]{1,80}$)([^\n]{1,80})\s/g, '$1\n');
45001 tidy : function(node, indent) {
45003 if (node.nodeType == 3) {
45007 return indent === false ? node.nodeValue : this.wrap(node.nodeValue.trim()).split("\n").join("\n" + indent);
45012 if (node.nodeType != 1) {
45018 if (node.tagName == 'BODY') {
45020 return this.cn(node, '');
45023 // Prints the node tagName, such as <A>, <IMG>, etc
45024 var ret = "<" + node.tagName + this.attr(node) ;
45026 // elements with no children..
45027 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(node.tagName) > -1) {
45033 var cindent = indent === false ? '' : (indent + ' ');
45034 // tags where we will not pad the children.. (inline text tags etc..)
45035 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN', 'B', 'I', 'S'].indexOf(node.tagName) > -1) { // or code?
45041 var cn = this.cn(node, cindent );
45043 return ret + cn + '</' + node.tagName + '>';
45046 cn: function(node, indent)
45050 var ar = Array.from(node.childNodes);
45051 for (var i = 0 ; i < ar.length ; i++) {
45052 if (indent !== false // indent==false preservies everything
45054 && ar[i].nodeType == 3
45055 && ar[i].nodeValue.length > 0
45056 && ar[i].nodeValue.match(/^\s+/)
45058 ret.push(" "); // add a space if i'm a text item with a space at the front, as tidy will strip spaces.
45060 if (indent !== false
45061 && ar[i].nodeType == 1 // element - and indent is not set...
45063 ret.push("\n" + indent);
45066 ret.push(this.tidy(ar[i], indent));
45067 // text + trailing indent
45068 if (indent !== false
45069 && ar[i].nodeType == 3
45070 && ar[i].nodeValue.length > 0
45071 && ar[i].nodeValue.match(/\s+$/)
45073 ret.push("\n" + indent);
45080 // what if all text?
45083 return ret.join('');
45088 attr : function(node)
45091 for(i = 0; i < node.attributes.length;i++) {
45093 // skip empty values?
45094 if (!node.attributes.item(i).value.length) {
45097 attr.push( node.attributes.item(i).name + '="' +
45098 Roo.util.Format.htmlEncode(node.attributes.item(i).value) + '"'
45101 return attr.length ? (' ' + attr.join(' ') ) : '';
45109 * @class Roo.htmleditor.KeyEnter
45110 * Handle Enter press..
45111 * @cfg {Roo.HtmlEditorCore} core the editor.
45113 * Create a new Filter.
45114 * @param {Object} config Configuration options
45119 Roo.htmleditor.KeyEnter = function(cfg) {
45120 Roo.apply(this, cfg);
45121 // this does not actually call walk as it's really just a abstract class
45123 Roo.get(this.core.doc.body).on('keypress', this.keypress, this);
45127 Roo.htmleditor.KeyEnter.prototype = {
45131 keypress : function(e) {
45132 if (e.charCode != 13) {
45135 e.preventDefault();
45136 // https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
45137 var doc = this.core.doc;
45139 var docFragment = doc.createDocumentFragment();
45142 var newEle = doc.createTextNode('\n');
45143 docFragment.appendChild(newEle);
45145 //add the br, or p, or something else
45146 newEle = doc.createElement('br');
45147 docFragment.appendChild(newEle);
45149 //make the br replace selection
45150 var range = this.core.win.getSelection().getRangeAt(0);
45151 range.deleteContents();
45152 range.insertNode(docFragment);
45154 //create a new range
45155 range = doc.createRange();
45156 range.setStartAfter(newEle);
45157 range.collapse(true);
45159 //make the cursor there
45160 var sel = this.core.win.getSelection();
45161 sel.removeAllRanges();
45162 sel.addRange(range);
45168 //<script type="text/javascript">
45171 * Based Ext JS Library 1.1.1
45172 * Copyright(c) 2006-2007, Ext JS, LLC.
45178 * @class Roo.HtmlEditorCore
45179 * @extends Roo.Component
45180 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
45182 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45185 Roo.HtmlEditorCore = function(config){
45188 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
45193 * @event initialize
45194 * Fires when the editor is fully initialized (including the iframe)
45195 * @param {Roo.HtmlEditorCore} this
45200 * Fires when the editor is first receives the focus. Any insertion must wait
45201 * until after this event.
45202 * @param {Roo.HtmlEditorCore} this
45206 * @event beforesync
45207 * Fires before the textarea is updated with content from the editor iframe. Return false
45208 * to cancel the sync.
45209 * @param {Roo.HtmlEditorCore} this
45210 * @param {String} html
45214 * @event beforepush
45215 * Fires before the iframe editor is updated with content from the textarea. Return false
45216 * to cancel the push.
45217 * @param {Roo.HtmlEditorCore} this
45218 * @param {String} html
45223 * Fires when the textarea is updated with content from the editor iframe.
45224 * @param {Roo.HtmlEditorCore} this
45225 * @param {String} html
45230 * Fires when the iframe editor is updated with content from the textarea.
45231 * @param {Roo.HtmlEditorCore} this
45232 * @param {String} html
45237 * @event editorevent
45238 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45239 * @param {Roo.HtmlEditorCore} this
45245 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
45247 // defaults : white / black...
45248 this.applyBlacklists();
45255 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
45259 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
45265 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45270 * @cfg {Number} height (in pixels)
45274 * @cfg {Number} width (in pixels)
45279 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45282 stylesheets: false,
45285 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
45287 allowComments: false,
45291 // private properties
45292 validationEvent : false,
45294 initialized : false,
45296 sourceEditMode : false,
45297 onFocus : Roo.emptyFn,
45299 hideMode:'offsets',
45303 // blacklist + whitelisted elements..
45310 * Protected method that will not generally be called directly. It
45311 * is called when the editor initializes the iframe with HTML contents. Override this method if you
45312 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
45314 getDocMarkup : function(){
45318 // inherit styels from page...??
45319 if (this.stylesheets === false) {
45321 Roo.get(document.head).select('style').each(function(node) {
45322 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
45325 Roo.get(document.head).select('link').each(function(node) {
45326 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
45329 } else if (!this.stylesheets.length) {
45331 st = '<style type="text/css">' +
45332 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
45335 for (var i in this.stylesheets) {
45336 if (typeof(this.stylesheets[i]) != 'string') {
45339 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
45344 st += '<style type="text/css">' +
45345 'IMG { cursor: pointer } ' +
45348 var cls = 'roo-htmleditor-body';
45350 if(this.bodyCls.length){
45351 cls += ' ' + this.bodyCls;
45354 return '<html><head>' + st +
45355 //<style type="text/css">' +
45356 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
45358 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
45362 onRender : function(ct, position)
45365 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
45366 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
45369 this.el.dom.style.border = '0 none';
45370 this.el.dom.setAttribute('tabIndex', -1);
45371 this.el.addClass('x-hidden hide');
45375 if(Roo.isIE){ // fix IE 1px bogus margin
45376 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
45380 this.frameId = Roo.id();
45384 var iframe = this.owner.wrap.createChild({
45386 cls: 'form-control', // bootstrap..
45388 name: this.frameId,
45389 frameBorder : 'no',
45390 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
45395 this.iframe = iframe.dom;
45397 this.assignDocWin();
45399 this.doc.designMode = 'on';
45402 this.doc.write(this.getDocMarkup());
45406 var task = { // must defer to wait for browser to be ready
45408 //console.log("run task?" + this.doc.readyState);
45409 this.assignDocWin();
45410 if(this.doc.body || this.doc.readyState == 'complete'){
45412 this.doc.designMode="on";
45416 Roo.TaskMgr.stop(task);
45417 this.initEditor.defer(10, this);
45424 Roo.TaskMgr.start(task);
45429 onResize : function(w, h)
45431 Roo.log('resize: ' +w + ',' + h );
45432 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
45436 if(typeof w == 'number'){
45438 this.iframe.style.width = w + 'px';
45440 if(typeof h == 'number'){
45442 this.iframe.style.height = h + 'px';
45444 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
45451 * Toggles the editor between standard and source edit mode.
45452 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45454 toggleSourceEdit : function(sourceEditMode){
45456 this.sourceEditMode = sourceEditMode === true;
45458 if(this.sourceEditMode){
45460 Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']); //FIXME - what's the BS styles for these
45463 Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']);
45464 //this.iframe.className = '';
45467 //this.setSize(this.owner.wrap.getSize());
45468 //this.fireEvent('editmodechange', this, this.sourceEditMode);
45475 * Protected method that will not generally be called directly. If you need/want
45476 * custom HTML cleanup, this is the method you should override.
45477 * @param {String} html The HTML to be cleaned
45478 * return {String} The cleaned HTML
45480 cleanHtml : function(html){
45481 html = String(html);
45482 if(html.length > 5){
45483 if(Roo.isSafari){ // strip safari nonsense
45484 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
45487 if(html == ' '){
45494 * HTML Editor -> Textarea
45495 * Protected method that will not generally be called directly. Syncs the contents
45496 * of the editor iframe with the textarea.
45498 syncValue : function(){
45499 if(this.initialized){
45500 var bd = (this.doc.body || this.doc.documentElement);
45501 //this.cleanUpPaste(); -- this is done else where and causes havoc..
45502 var html = bd.innerHTML;
45504 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
45505 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
45507 html = '<div style="'+m[0]+'">' + html + '</div>';
45510 html = this.cleanHtml(html);
45511 // fix up the special chars.. normaly like back quotes in word...
45512 // however we do not want to do this with chinese..
45513 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
45515 var cc = match.charCodeAt();
45517 // Get the character value, handling surrogate pairs
45518 if (match.length == 2) {
45519 // It's a surrogate pair, calculate the Unicode code point
45520 var high = match.charCodeAt(0) - 0xD800;
45521 var low = match.charCodeAt(1) - 0xDC00;
45522 cc = (high * 0x400) + low + 0x10000;
45524 (cc >= 0x4E00 && cc < 0xA000 ) ||
45525 (cc >= 0x3400 && cc < 0x4E00 ) ||
45526 (cc >= 0xf900 && cc < 0xfb00 )
45531 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
45532 return "&#" + cc + ";";
45539 if(this.owner.fireEvent('beforesync', this, html) !== false){
45540 this.el.dom.value = html;
45541 this.owner.fireEvent('sync', this, html);
45547 * Protected method that will not generally be called directly. Pushes the value of the textarea
45548 * into the iframe editor.
45550 pushValue : function(){
45551 if(this.initialized){
45552 var v = this.el.dom.value.trim();
45554 // if(v.length < 1){
45558 if(this.owner.fireEvent('beforepush', this, v) !== false){
45559 var d = (this.doc.body || this.doc.documentElement);
45561 this.cleanUpPaste();
45562 this.el.dom.value = d.innerHTML;
45563 this.owner.fireEvent('push', this, v);
45569 deferFocus : function(){
45570 this.focus.defer(10, this);
45574 focus : function(){
45575 if(this.win && !this.sourceEditMode){
45582 assignDocWin: function()
45584 var iframe = this.iframe;
45587 this.doc = iframe.contentWindow.document;
45588 this.win = iframe.contentWindow;
45590 // if (!Roo.get(this.frameId)) {
45593 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
45594 // this.win = Roo.get(this.frameId).dom.contentWindow;
45596 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
45600 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
45601 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
45606 initEditor : function(){
45607 //console.log("INIT EDITOR");
45608 this.assignDocWin();
45612 this.doc.designMode="on";
45614 this.doc.write(this.getDocMarkup());
45617 var dbody = (this.doc.body || this.doc.documentElement);
45618 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
45619 // this copies styles from the containing element into thsi one..
45620 // not sure why we need all of this..
45621 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
45623 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
45624 //ss['background-attachment'] = 'fixed'; // w3c
45625 dbody.bgProperties = 'fixed'; // ie
45626 //Roo.DomHelper.applyStyles(dbody, ss);
45627 Roo.EventManager.on(this.doc, {
45628 //'mousedown': this.onEditorEvent,
45629 'mouseup': this.onEditorEvent,
45630 'dblclick': this.onEditorEvent,
45631 'click': this.onEditorEvent,
45632 'keyup': this.onEditorEvent,
45637 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
45639 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
45640 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
45642 this.initialized = true;
45645 // initialize special key events - enter
45646 new Roo.htmleditor.KeyEnter({core : this});
45651 this.owner.fireEvent('initialize', this);
45656 onDestroy : function(){
45662 //for (var i =0; i < this.toolbars.length;i++) {
45663 // // fixme - ask toolbars for heights?
45664 // this.toolbars[i].onDestroy();
45667 //this.wrap.dom.innerHTML = '';
45668 //this.wrap.remove();
45673 onFirstFocus : function(){
45675 this.assignDocWin();
45678 this.activated = true;
45681 if(Roo.isGecko){ // prevent silly gecko errors
45683 var s = this.win.getSelection();
45684 if(!s.focusNode || s.focusNode.nodeType != 3){
45685 var r = s.getRangeAt(0);
45686 r.selectNodeContents((this.doc.body || this.doc.documentElement));
45691 this.execCmd('useCSS', true);
45692 this.execCmd('styleWithCSS', false);
45695 this.owner.fireEvent('activate', this);
45699 adjustFont: function(btn){
45700 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
45701 //if(Roo.isSafari){ // safari
45704 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
45705 if(Roo.isSafari){ // safari
45706 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
45707 v = (v < 10) ? 10 : v;
45708 v = (v > 48) ? 48 : v;
45709 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
45714 v = Math.max(1, v+adjust);
45716 this.execCmd('FontSize', v );
45719 onEditorEvent : function(e)
45721 this.owner.fireEvent('editorevent', this, e);
45722 // this.updateToolbar();
45723 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
45726 insertTag : function(tg)
45728 // could be a bit smarter... -> wrap the current selected tRoo..
45729 if (tg.toLowerCase() == 'span' ||
45730 tg.toLowerCase() == 'code' ||
45731 tg.toLowerCase() == 'sup' ||
45732 tg.toLowerCase() == 'sub'
45735 range = this.createRange(this.getSelection());
45736 var wrappingNode = this.doc.createElement(tg.toLowerCase());
45737 wrappingNode.appendChild(range.extractContents());
45738 range.insertNode(wrappingNode);
45745 this.execCmd("formatblock", tg);
45749 insertText : function(txt)
45753 var range = this.createRange();
45754 range.deleteContents();
45755 //alert(Sender.getAttribute('label'));
45757 range.insertNode(this.doc.createTextNode(txt));
45763 * Executes a Midas editor command on the editor document and performs necessary focus and
45764 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
45765 * @param {String} cmd The Midas command
45766 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
45768 relayCmd : function(cmd, value){
45770 this.execCmd(cmd, value);
45771 this.owner.fireEvent('editorevent', this);
45772 //this.updateToolbar();
45773 this.owner.deferFocus();
45777 * Executes a Midas editor command directly on the editor document.
45778 * For visual commands, you should use {@link #relayCmd} instead.
45779 * <b>This should only be called after the editor is initialized.</b>
45780 * @param {String} cmd The Midas command
45781 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
45783 execCmd : function(cmd, value){
45784 this.doc.execCommand(cmd, false, value === undefined ? null : value);
45791 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
45793 * @param {String} text | dom node..
45795 insertAtCursor : function(text)
45798 if(!this.activated){
45804 var r = this.doc.selection.createRange();
45815 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
45819 // from jquery ui (MIT licenced)
45821 var win = this.win;
45823 if (win.getSelection && win.getSelection().getRangeAt) {
45824 range = win.getSelection().getRangeAt(0);
45825 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
45826 range.insertNode(node);
45827 } else if (win.document.selection && win.document.selection.createRange) {
45828 // no firefox support
45829 var txt = typeof(text) == 'string' ? text : text.outerHTML;
45830 win.document.selection.createRange().pasteHTML(txt);
45832 // no firefox support
45833 var txt = typeof(text) == 'string' ? text : text.outerHTML;
45834 this.execCmd('InsertHTML', txt);
45843 mozKeyPress : function(e){
45845 var c = e.getCharCode(), cmd;
45848 c = String.fromCharCode(c).toLowerCase();
45862 this.cleanUpPaste.defer(100, this);
45870 e.preventDefault();
45878 fixKeys : function(){ // load time branching for fastest keydown performance
45880 return function(e){
45881 var k = e.getKey(), r;
45884 r = this.doc.selection.createRange();
45887 r.pasteHTML('    ');
45894 r = this.doc.selection.createRange();
45896 var target = r.parentElement();
45897 if(!target || target.tagName.toLowerCase() != 'li'){
45899 r.pasteHTML('<br />');
45905 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
45906 this.cleanUpPaste.defer(100, this);
45912 }else if(Roo.isOpera){
45913 return function(e){
45914 var k = e.getKey();
45918 this.execCmd('InsertHTML','    ');
45921 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
45922 this.cleanUpPaste.defer(100, this);
45927 }else if(Roo.isSafari){
45928 return function(e){
45929 var k = e.getKey();
45933 this.execCmd('InsertText','\t');
45937 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
45938 this.cleanUpPaste.defer(100, this);
45946 getAllAncestors: function()
45948 var p = this.getSelectedNode();
45951 a.push(p); // push blank onto stack..
45952 p = this.getParentElement();
45956 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
45960 a.push(this.doc.body);
45964 lastSelNode : false,
45967 getSelection : function()
45969 this.assignDocWin();
45970 return Roo.isIE ? this.doc.selection : this.win.getSelection();
45973 getSelectedNode: function()
45975 // this may only work on Gecko!!!
45977 // should we cache this!!!!
45982 var range = this.createRange(this.getSelection()).cloneRange();
45985 var parent = range.parentElement();
45987 var testRange = range.duplicate();
45988 testRange.moveToElementText(parent);
45989 if (testRange.inRange(range)) {
45992 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
45995 parent = parent.parentElement;
46000 // is ancestor a text element.
46001 var ac = range.commonAncestorContainer;
46002 if (ac.nodeType == 3) {
46003 ac = ac.parentNode;
46006 var ar = ac.childNodes;
46009 var other_nodes = [];
46010 var has_other_nodes = false;
46011 for (var i=0;i<ar.length;i++) {
46012 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
46015 // fullly contained node.
46017 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
46022 // probably selected..
46023 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
46024 other_nodes.push(ar[i]);
46028 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
46033 has_other_nodes = true;
46035 if (!nodes.length && other_nodes.length) {
46036 nodes= other_nodes;
46038 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
46044 createRange: function(sel)
46046 // this has strange effects when using with
46047 // top toolbar - not sure if it's a great idea.
46048 //this.editor.contentWindow.focus();
46049 if (typeof sel != "undefined") {
46051 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
46053 return this.doc.createRange();
46056 return this.doc.createRange();
46059 getParentElement: function()
46062 this.assignDocWin();
46063 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
46065 var range = this.createRange(sel);
46068 var p = range.commonAncestorContainer;
46069 while (p.nodeType == 3) { // text node
46080 * Range intersection.. the hard stuff...
46084 * [ -- selected range --- ]
46088 * if end is before start or hits it. fail.
46089 * if start is after end or hits it fail.
46091 * if either hits (but other is outside. - then it's not
46097 // @see http://www.thismuchiknow.co.uk/?p=64.
46098 rangeIntersectsNode : function(range, node)
46100 var nodeRange = node.ownerDocument.createRange();
46102 nodeRange.selectNode(node);
46104 nodeRange.selectNodeContents(node);
46107 var rangeStartRange = range.cloneRange();
46108 rangeStartRange.collapse(true);
46110 var rangeEndRange = range.cloneRange();
46111 rangeEndRange.collapse(false);
46113 var nodeStartRange = nodeRange.cloneRange();
46114 nodeStartRange.collapse(true);
46116 var nodeEndRange = nodeRange.cloneRange();
46117 nodeEndRange.collapse(false);
46119 return rangeStartRange.compareBoundaryPoints(
46120 Range.START_TO_START, nodeEndRange) == -1 &&
46121 rangeEndRange.compareBoundaryPoints(
46122 Range.START_TO_START, nodeStartRange) == 1;
46126 rangeCompareNode : function(range, node)
46128 var nodeRange = node.ownerDocument.createRange();
46130 nodeRange.selectNode(node);
46132 nodeRange.selectNodeContents(node);
46136 range.collapse(true);
46138 nodeRange.collapse(true);
46140 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
46141 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
46143 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
46145 var nodeIsBefore = ss == 1;
46146 var nodeIsAfter = ee == -1;
46148 if (nodeIsBefore && nodeIsAfter) {
46151 if (!nodeIsBefore && nodeIsAfter) {
46152 return 1; //right trailed.
46155 if (nodeIsBefore && !nodeIsAfter) {
46156 return 2; // left trailed.
46162 // private? - in a new class?
46163 cleanUpPaste : function()
46165 // cleans up the whole document..
46166 Roo.log('cleanuppaste');
46168 this.cleanUpChild(this.doc.body);
46169 var clean = this.cleanWordChars(this.doc.body.innerHTML);
46170 if (clean != this.doc.body.innerHTML) {
46171 this.doc.body.innerHTML = clean;
46176 cleanWordChars : function(input) {// change the chars to hex code
46177 var he = Roo.HtmlEditorCore;
46179 var output = input;
46180 Roo.each(he.swapCodes, function(sw) {
46181 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
46183 output = output.replace(swapper, sw[1]);
46193 cleanUpChild : function (node)
46196 new Roo.htmleditor.FilterComment({node : node});
46197 new Roo.htmleditor.FilterAttributes({
46199 attrib_black : this.ablack,
46200 attrib_clean : this.aclean,
46201 style_white : this.cwhite,
46202 style_black : this.cblack
46204 new Roo.htmleditor.FilterBlack({ node : node, tag : this.black});
46205 new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} );
46211 * Clean up MS wordisms...
46212 * @deprecated - use filter directly
46214 cleanWord : function(node)
46216 new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
46223 * @deprecated - use filters
46225 cleanTableWidths : function(node)
46227 new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
46234 applyBlacklists : function()
46236 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
46237 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
46239 this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean : Roo.HtmlEditorCore.aclean;
46240 this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack : Roo.HtmlEditorCore.ablack;
46241 this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove : Roo.HtmlEditorCore.tag_remove;
46245 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
46246 if (b.indexOf(tag) > -1) {
46249 this.white.push(tag);
46253 Roo.each(w, function(tag) {
46254 if (b.indexOf(tag) > -1) {
46257 if (this.white.indexOf(tag) > -1) {
46260 this.white.push(tag);
46265 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
46266 if (w.indexOf(tag) > -1) {
46269 this.black.push(tag);
46273 Roo.each(b, function(tag) {
46274 if (w.indexOf(tag) > -1) {
46277 if (this.black.indexOf(tag) > -1) {
46280 this.black.push(tag);
46285 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
46286 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
46290 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
46291 if (b.indexOf(tag) > -1) {
46294 this.cwhite.push(tag);
46298 Roo.each(w, function(tag) {
46299 if (b.indexOf(tag) > -1) {
46302 if (this.cwhite.indexOf(tag) > -1) {
46305 this.cwhite.push(tag);
46310 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
46311 if (w.indexOf(tag) > -1) {
46314 this.cblack.push(tag);
46318 Roo.each(b, function(tag) {
46319 if (w.indexOf(tag) > -1) {
46322 if (this.cblack.indexOf(tag) > -1) {
46325 this.cblack.push(tag);
46330 setStylesheets : function(stylesheets)
46332 if(typeof(stylesheets) == 'string'){
46333 Roo.get(this.iframe.contentDocument.head).createChild({
46335 rel : 'stylesheet',
46344 Roo.each(stylesheets, function(s) {
46349 Roo.get(_this.iframe.contentDocument.head).createChild({
46351 rel : 'stylesheet',
46360 removeStylesheets : function()
46364 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
46369 setStyle : function(style)
46371 Roo.get(this.iframe.contentDocument.head).createChild({
46380 // hide stuff that is not compatible
46394 * @event specialkey
46398 * @cfg {String} fieldClass @hide
46401 * @cfg {String} focusClass @hide
46404 * @cfg {String} autoCreate @hide
46407 * @cfg {String} inputType @hide
46410 * @cfg {String} invalidClass @hide
46413 * @cfg {String} invalidText @hide
46416 * @cfg {String} msgFx @hide
46419 * @cfg {String} validateOnBlur @hide
46423 Roo.HtmlEditorCore.white = [
46424 'area', 'br', 'img', 'input', 'hr', 'wbr',
46426 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
46427 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
46428 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
46429 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
46430 'table', 'ul', 'xmp',
46432 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
46435 'dir', 'menu', 'ol', 'ul', 'dl',
46441 Roo.HtmlEditorCore.black = [
46442 // 'embed', 'object', // enable - backend responsiblity to clean thiese
46444 'base', 'basefont', 'bgsound', 'blink', 'body',
46445 'frame', 'frameset', 'head', 'html', 'ilayer',
46446 'iframe', 'layer', 'link', 'meta', 'object',
46447 'script', 'style' ,'title', 'xml' // clean later..
46449 Roo.HtmlEditorCore.clean = [
46450 'script', 'style', 'title', 'xml'
46452 Roo.HtmlEditorCore.tag_remove = [
46457 Roo.HtmlEditorCore.ablack = [
46461 Roo.HtmlEditorCore.aclean = [
46462 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
46466 Roo.HtmlEditorCore.pwhite= [
46467 'http', 'https', 'mailto'
46470 // white listed style attributes.
46471 Roo.HtmlEditorCore.cwhite= [
46472 // 'text-align', /// default is to allow most things..
46478 // black listed style attributes.
46479 Roo.HtmlEditorCore.cblack= [
46480 // 'font-size' -- this can be set by the project
46484 Roo.HtmlEditorCore.swapCodes =[
46485 [ 8211, "–" ],
46486 [ 8212, "—" ],
46495 //<script type="text/javascript">
46498 * Ext JS Library 1.1.1
46499 * Copyright(c) 2006-2007, Ext JS, LLC.
46505 Roo.form.HtmlEditor = function(config){
46509 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
46511 if (!this.toolbars) {
46512 this.toolbars = [];
46514 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
46520 * @class Roo.form.HtmlEditor
46521 * @extends Roo.form.Field
46522 * Provides a lightweight HTML Editor component.
46524 * This has been tested on Fireforx / Chrome.. IE may not be so great..
46526 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
46527 * supported by this editor.</b><br/><br/>
46528 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
46529 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
46531 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
46533 * @cfg {Boolean} clearUp
46537 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
46542 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
46547 * @cfg {Number} height (in pixels)
46551 * @cfg {Number} width (in pixels)
46556 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets - this is usally a good idea rootURL + '/roojs1/css/undoreset.css', .
46559 stylesheets: false,
46563 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
46568 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
46574 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
46579 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
46584 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
46586 allowComments: false,
46588 * @cfg {string} bodyCls- default '' default classes to add to body of editable area - usually undoreset is a good start..
46597 // private properties
46598 validationEvent : false,
46600 initialized : false,
46603 onFocus : Roo.emptyFn,
46605 hideMode:'offsets',
46607 actionMode : 'container', // defaults to hiding it...
46609 defaultAutoCreate : { // modified by initCompnoent..
46611 style:"width:500px;height:300px;",
46612 autocomplete: "new-password"
46616 initComponent : function(){
46619 * @event initialize
46620 * Fires when the editor is fully initialized (including the iframe)
46621 * @param {HtmlEditor} this
46626 * Fires when the editor is first receives the focus. Any insertion must wait
46627 * until after this event.
46628 * @param {HtmlEditor} this
46632 * @event beforesync
46633 * Fires before the textarea is updated with content from the editor iframe. Return false
46634 * to cancel the sync.
46635 * @param {HtmlEditor} this
46636 * @param {String} html
46640 * @event beforepush
46641 * Fires before the iframe editor is updated with content from the textarea. Return false
46642 * to cancel the push.
46643 * @param {HtmlEditor} this
46644 * @param {String} html
46649 * Fires when the textarea is updated with content from the editor iframe.
46650 * @param {HtmlEditor} this
46651 * @param {String} html
46656 * Fires when the iframe editor is updated with content from the textarea.
46657 * @param {HtmlEditor} this
46658 * @param {String} html
46662 * @event editmodechange
46663 * Fires when the editor switches edit modes
46664 * @param {HtmlEditor} this
46665 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
46667 editmodechange: true,
46669 * @event editorevent
46670 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
46671 * @param {HtmlEditor} this
46675 * @event firstfocus
46676 * Fires when on first focus - needed by toolbars..
46677 * @param {HtmlEditor} this
46682 * Auto save the htmlEditor value as a file into Events
46683 * @param {HtmlEditor} this
46687 * @event savedpreview
46688 * preview the saved version of htmlEditor
46689 * @param {HtmlEditor} this
46691 savedpreview: true,
46694 * @event stylesheetsclick
46695 * Fires when press the Sytlesheets button
46696 * @param {Roo.HtmlEditorCore} this
46698 stylesheetsclick: true
46700 this.defaultAutoCreate = {
46702 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
46703 autocomplete: "new-password"
46708 * Protected method that will not generally be called directly. It
46709 * is called when the editor creates its toolbar. Override this method if you need to
46710 * add custom toolbar buttons.
46711 * @param {HtmlEditor} editor
46713 createToolbar : function(editor){
46714 Roo.log("create toolbars");
46715 if (!editor.toolbars || !editor.toolbars.length) {
46716 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
46719 for (var i =0 ; i < editor.toolbars.length;i++) {
46720 editor.toolbars[i] = Roo.factory(
46721 typeof(editor.toolbars[i]) == 'string' ?
46722 { xtype: editor.toolbars[i]} : editor.toolbars[i],
46723 Roo.form.HtmlEditor);
46724 editor.toolbars[i].init(editor);
46732 onRender : function(ct, position)
46735 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
46737 this.wrap = this.el.wrap({
46738 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
46741 this.editorcore.onRender(ct, position);
46743 if (this.resizable) {
46744 this.resizeEl = new Roo.Resizable(this.wrap, {
46748 minHeight : this.height,
46749 height: this.height,
46750 handles : this.resizable,
46753 resize : function(r, w, h) {
46754 _t.onResize(w,h); // -something
46760 this.createToolbar(this);
46764 this.setSize(this.wrap.getSize());
46766 if (this.resizeEl) {
46767 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
46768 // should trigger onReize..
46771 this.keyNav = new Roo.KeyNav(this.el, {
46773 "tab" : function(e){
46774 e.preventDefault();
46776 var value = this.getValue();
46778 var start = this.el.dom.selectionStart;
46779 var end = this.el.dom.selectionEnd;
46783 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
46784 this.el.dom.setSelectionRange(end + 1, end + 1);
46788 var f = value.substring(0, start).split("\t");
46790 if(f.pop().length != 0){
46794 this.setValue(f.join("\t") + value.substring(end));
46795 this.el.dom.setSelectionRange(start - 1, start - 1);
46799 "home" : function(e){
46800 e.preventDefault();
46802 var curr = this.el.dom.selectionStart;
46803 var lines = this.getValue().split("\n");
46810 this.el.dom.setSelectionRange(0, 0);
46816 for (var i = 0; i < lines.length;i++) {
46817 pos += lines[i].length;
46827 pos -= lines[i].length;
46833 this.el.dom.setSelectionRange(pos, pos);
46837 this.el.dom.selectionStart = pos;
46838 this.el.dom.selectionEnd = curr;
46841 "end" : function(e){
46842 e.preventDefault();
46844 var curr = this.el.dom.selectionStart;
46845 var lines = this.getValue().split("\n");
46852 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
46858 for (var i = 0; i < lines.length;i++) {
46860 pos += lines[i].length;
46874 this.el.dom.setSelectionRange(pos, pos);
46878 this.el.dom.selectionStart = curr;
46879 this.el.dom.selectionEnd = pos;
46884 doRelay : function(foo, bar, hname){
46885 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
46891 // if(this.autosave && this.w){
46892 // this.autoSaveFn = setInterval(this.autosave, 1000);
46897 onResize : function(w, h)
46899 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
46904 if(typeof w == 'number'){
46905 var aw = w - this.wrap.getFrameWidth('lr');
46906 this.el.setWidth(this.adjustWidth('textarea', aw));
46909 if(typeof h == 'number'){
46911 for (var i =0; i < this.toolbars.length;i++) {
46912 // fixme - ask toolbars for heights?
46913 tbh += this.toolbars[i].tb.el.getHeight();
46914 if (this.toolbars[i].footer) {
46915 tbh += this.toolbars[i].footer.el.getHeight();
46922 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
46923 ah -= 5; // knock a few pixes off for look..
46925 this.el.setHeight(this.adjustWidth('textarea', ah));
46929 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
46930 this.editorcore.onResize(ew,eh);
46935 * Toggles the editor between standard and source edit mode.
46936 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
46938 toggleSourceEdit : function(sourceEditMode)
46940 this.editorcore.toggleSourceEdit(sourceEditMode);
46942 if(this.editorcore.sourceEditMode){
46943 Roo.log('editor - showing textarea');
46946 // Roo.log(this.syncValue());
46947 this.editorcore.syncValue();
46948 this.el.removeClass('x-hidden');
46949 this.el.dom.removeAttribute('tabIndex');
46951 this.el.dom.scrollTop = 0;
46954 for (var i = 0; i < this.toolbars.length; i++) {
46955 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
46956 this.toolbars[i].tb.hide();
46957 this.toolbars[i].footer.hide();
46962 Roo.log('editor - hiding textarea');
46964 // Roo.log(this.pushValue());
46965 this.editorcore.pushValue();
46967 this.el.addClass('x-hidden');
46968 this.el.dom.setAttribute('tabIndex', -1);
46970 for (var i = 0; i < this.toolbars.length; i++) {
46971 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
46972 this.toolbars[i].tb.show();
46973 this.toolbars[i].footer.show();
46977 //this.deferFocus();
46980 this.setSize(this.wrap.getSize());
46981 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
46983 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
46986 // private (for BoxComponent)
46987 adjustSize : Roo.BoxComponent.prototype.adjustSize,
46989 // private (for BoxComponent)
46990 getResizeEl : function(){
46994 // private (for BoxComponent)
46995 getPositionEl : function(){
47000 initEvents : function(){
47001 this.originalValue = this.getValue();
47005 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
47008 markInvalid : Roo.emptyFn,
47010 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
47013 clearInvalid : Roo.emptyFn,
47015 setValue : function(v){
47016 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
47017 this.editorcore.pushValue();
47022 deferFocus : function(){
47023 this.focus.defer(10, this);
47027 focus : function(){
47028 this.editorcore.focus();
47034 onDestroy : function(){
47040 for (var i =0; i < this.toolbars.length;i++) {
47041 // fixme - ask toolbars for heights?
47042 this.toolbars[i].onDestroy();
47045 this.wrap.dom.innerHTML = '';
47046 this.wrap.remove();
47051 onFirstFocus : function(){
47052 //Roo.log("onFirstFocus");
47053 this.editorcore.onFirstFocus();
47054 for (var i =0; i < this.toolbars.length;i++) {
47055 this.toolbars[i].onFirstFocus();
47061 syncValue : function()
47063 this.editorcore.syncValue();
47066 pushValue : function()
47068 this.editorcore.pushValue();
47071 setStylesheets : function(stylesheets)
47073 this.editorcore.setStylesheets(stylesheets);
47076 removeStylesheets : function()
47078 this.editorcore.removeStylesheets();
47082 // hide stuff that is not compatible
47096 * @event specialkey
47100 * @cfg {String} fieldClass @hide
47103 * @cfg {String} focusClass @hide
47106 * @cfg {String} autoCreate @hide
47109 * @cfg {String} inputType @hide
47112 * @cfg {String} invalidClass @hide
47115 * @cfg {String} invalidText @hide
47118 * @cfg {String} msgFx @hide
47121 * @cfg {String} validateOnBlur @hide
47125 // <script type="text/javascript">
47128 * Ext JS Library 1.1.1
47129 * Copyright(c) 2006-2007, Ext JS, LLC.
47135 * @class Roo.form.HtmlEditorToolbar1
47140 new Roo.form.HtmlEditor({
47143 new Roo.form.HtmlEditorToolbar1({
47144 disable : { fonts: 1 , format: 1, ..., ... , ...],
47150 * @cfg {Object} disable List of elements to disable..
47151 * @cfg {Array} btns List of additional buttons.
47155 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
47158 Roo.form.HtmlEditor.ToolbarStandard = function(config)
47161 Roo.apply(this, config);
47163 // default disabled, based on 'good practice'..
47164 this.disable = this.disable || {};
47165 Roo.applyIf(this.disable, {
47168 specialElements : true
47172 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
47173 // dont call parent... till later.
47176 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
47183 editorcore : false,
47185 * @cfg {Object} disable List of toolbar elements to disable
47192 * @cfg {String} createLinkText The default text for the create link prompt
47194 createLinkText : 'Please enter the URL for the link:',
47196 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
47198 defaultLinkValue : 'http:/'+'/',
47202 * @cfg {Array} fontFamilies An array of available font families
47220 // "á" , ?? a acute?
47225 "°" // , // degrees
47227 // "é" , // e ecute
47228 // "ú" , // u ecute?
47231 specialElements : [
47233 text: "Insert Table",
47236 ihtml : '<table><tr><td>Cell</td></tr></table>'
47240 text: "Insert Image",
47243 ihtml : '<img src="about:blank"/>'
47252 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
47253 "input:submit", "input:button", "select", "textarea", "label" ],
47256 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
47258 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
47267 * @cfg {String} defaultFont default font to use.
47269 defaultFont: 'tahoma',
47271 fontSelect : false,
47274 formatCombo : false,
47276 init : function(editor)
47278 this.editor = editor;
47279 this.editorcore = editor.editorcore ? editor.editorcore : editor;
47280 var editorcore = this.editorcore;
47284 var fid = editorcore.frameId;
47286 function btn(id, toggle, handler){
47287 var xid = fid + '-'+ id ;
47291 cls : 'x-btn-icon x-edit-'+id,
47292 enableToggle:toggle !== false,
47293 scope: _t, // was editor...
47294 handler:handler||_t.relayBtnCmd,
47295 clickEvent:'mousedown',
47296 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47303 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47305 // stop form submits
47306 tb.el.on('click', function(e){
47307 e.preventDefault(); // what does this do?
47310 if(!this.disable.font) { // && !Roo.isSafari){
47311 /* why no safari for fonts
47312 editor.fontSelect = tb.el.createChild({
47315 cls:'x-font-select',
47316 html: this.createFontOptions()
47319 editor.fontSelect.on('change', function(){
47320 var font = editor.fontSelect.dom.value;
47321 editor.relayCmd('fontname', font);
47322 editor.deferFocus();
47326 editor.fontSelect.dom,
47332 if(!this.disable.formats){
47333 this.formatCombo = new Roo.form.ComboBox({
47334 store: new Roo.data.SimpleStore({
47337 data : this.formats // from states.js
47341 //autoCreate : {tag: "div", size: "20"},
47342 displayField:'tag',
47346 triggerAction: 'all',
47347 emptyText:'Add tag',
47348 selectOnFocus:true,
47351 'select': function(c, r, i) {
47352 editorcore.insertTag(r.get('tag'));
47358 tb.addField(this.formatCombo);
47362 if(!this.disable.format){
47367 btn('strikethrough')
47370 if(!this.disable.fontSize){
47375 btn('increasefontsize', false, editorcore.adjustFont),
47376 btn('decreasefontsize', false, editorcore.adjustFont)
47381 if(!this.disable.colors){
47384 id:editorcore.frameId +'-forecolor',
47385 cls:'x-btn-icon x-edit-forecolor',
47386 clickEvent:'mousedown',
47387 tooltip: this.buttonTips['forecolor'] || undefined,
47389 menu : new Roo.menu.ColorMenu({
47390 allowReselect: true,
47391 focus: Roo.emptyFn,
47394 selectHandler: function(cp, color){
47395 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
47396 editor.deferFocus();
47399 clickEvent:'mousedown'
47402 id:editorcore.frameId +'backcolor',
47403 cls:'x-btn-icon x-edit-backcolor',
47404 clickEvent:'mousedown',
47405 tooltip: this.buttonTips['backcolor'] || undefined,
47407 menu : new Roo.menu.ColorMenu({
47408 focus: Roo.emptyFn,
47411 allowReselect: true,
47412 selectHandler: function(cp, color){
47414 editorcore.execCmd('useCSS', false);
47415 editorcore.execCmd('hilitecolor', color);
47416 editorcore.execCmd('useCSS', true);
47417 editor.deferFocus();
47419 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
47420 Roo.isSafari || Roo.isIE ? '#'+color : color);
47421 editor.deferFocus();
47425 clickEvent:'mousedown'
47430 // now add all the items...
47433 if(!this.disable.alignments){
47436 btn('justifyleft'),
47437 btn('justifycenter'),
47438 btn('justifyright')
47442 //if(!Roo.isSafari){
47443 if(!this.disable.links){
47446 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
47450 if(!this.disable.lists){
47453 btn('insertorderedlist'),
47454 btn('insertunorderedlist')
47457 if(!this.disable.sourceEdit){
47460 btn('sourceedit', true, function(btn){
47461 this.toggleSourceEdit(btn.pressed);
47468 // special menu.. - needs to be tidied up..
47469 if (!this.disable.special) {
47472 cls: 'x-edit-none',
47478 for (var i =0; i < this.specialChars.length; i++) {
47479 smenu.menu.items.push({
47481 html: this.specialChars[i],
47482 handler: function(a,b) {
47483 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
47484 //editor.insertAtCursor(a.html);
47498 if (!this.disable.cleanStyles) {
47500 cls: 'x-btn-icon x-btn-clear',
47506 for (var i =0; i < this.cleanStyles.length; i++) {
47507 cmenu.menu.items.push({
47508 actiontype : this.cleanStyles[i],
47509 html: 'Remove ' + this.cleanStyles[i],
47510 handler: function(a,b) {
47513 var c = Roo.get(editorcore.doc.body);
47514 c.select('[style]').each(function(s) {
47515 s.dom.style.removeProperty(a.actiontype);
47517 editorcore.syncValue();
47522 cmenu.menu.items.push({
47523 actiontype : 'tablewidths',
47524 html: 'Remove Table Widths',
47525 handler: function(a,b) {
47526 editorcore.cleanTableWidths();
47527 editorcore.syncValue();
47531 cmenu.menu.items.push({
47532 actiontype : 'word',
47533 html: 'Remove MS Word Formating',
47534 handler: function(a,b) {
47535 editorcore.cleanWord();
47536 editorcore.syncValue();
47541 cmenu.menu.items.push({
47542 actiontype : 'all',
47543 html: 'Remove All Styles',
47544 handler: function(a,b) {
47546 var c = Roo.get(editorcore.doc.body);
47547 c.select('[style]').each(function(s) {
47548 s.dom.removeAttribute('style');
47550 editorcore.syncValue();
47555 cmenu.menu.items.push({
47556 actiontype : 'all',
47557 html: 'Remove All CSS Classes',
47558 handler: function(a,b) {
47560 var c = Roo.get(editorcore.doc.body);
47561 c.select('[class]').each(function(s) {
47562 s.dom.removeAttribute('class');
47564 editorcore.cleanWord();
47565 editorcore.syncValue();
47570 cmenu.menu.items.push({
47571 actiontype : 'tidy',
47572 html: 'Tidy HTML Source',
47573 handler: function(a,b) {
47574 new Roo.htmleditor.Tidy(editorcore.doc.body);
47575 editorcore.syncValue();
47584 if (!this.disable.specialElements) {
47587 cls: 'x-edit-none',
47592 for (var i =0; i < this.specialElements.length; i++) {
47593 semenu.menu.items.push(
47595 handler: function(a,b) {
47596 editor.insertAtCursor(this.ihtml);
47598 }, this.specialElements[i])
47610 for(var i =0; i< this.btns.length;i++) {
47611 var b = Roo.factory(this.btns[i],Roo.form);
47612 b.cls = 'x-edit-none';
47614 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
47615 b.cls += ' x-init-enable';
47618 b.scope = editorcore;
47626 // disable everything...
47628 this.tb.items.each(function(item){
47631 item.id != editorcore.frameId+ '-sourceedit' &&
47632 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
47638 this.rendered = true;
47640 // the all the btns;
47641 editor.on('editorevent', this.updateToolbar, this);
47642 // other toolbars need to implement this..
47643 //editor.on('editmodechange', this.updateToolbar, this);
47647 relayBtnCmd : function(btn) {
47648 this.editorcore.relayCmd(btn.cmd);
47650 // private used internally
47651 createLink : function(){
47652 Roo.log("create link?");
47653 var url = prompt(this.createLinkText, this.defaultLinkValue);
47654 if(url && url != 'http:/'+'/'){
47655 this.editorcore.relayCmd('createlink', url);
47661 * Protected method that will not generally be called directly. It triggers
47662 * a toolbar update by reading the markup state of the current selection in the editor.
47664 updateToolbar: function(){
47666 if(!this.editorcore.activated){
47667 this.editor.onFirstFocus();
47671 var btns = this.tb.items.map,
47672 doc = this.editorcore.doc,
47673 frameId = this.editorcore.frameId;
47675 if(!this.disable.font && !Roo.isSafari){
47677 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
47678 if(name != this.fontSelect.dom.value){
47679 this.fontSelect.dom.value = name;
47683 if(!this.disable.format){
47684 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
47685 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
47686 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
47687 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
47689 if(!this.disable.alignments){
47690 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
47691 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
47692 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
47694 if(!Roo.isSafari && !this.disable.lists){
47695 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
47696 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
47699 var ans = this.editorcore.getAllAncestors();
47700 if (this.formatCombo) {
47703 var store = this.formatCombo.store;
47704 this.formatCombo.setValue("");
47705 for (var i =0; i < ans.length;i++) {
47706 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
47708 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
47716 // hides menus... - so this cant be on a menu...
47717 Roo.menu.MenuMgr.hideAll();
47719 //this.editorsyncValue();
47723 createFontOptions : function(){
47724 var buf = [], fs = this.fontFamilies, ff, lc;
47728 for(var i = 0, len = fs.length; i< len; i++){
47730 lc = ff.toLowerCase();
47732 '<option value="',lc,'" style="font-family:',ff,';"',
47733 (this.defaultFont == lc ? ' selected="true">' : '>'),
47738 return buf.join('');
47741 toggleSourceEdit : function(sourceEditMode){
47743 Roo.log("toolbar toogle");
47744 if(sourceEditMode === undefined){
47745 sourceEditMode = !this.sourceEditMode;
47747 this.sourceEditMode = sourceEditMode === true;
47748 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
47749 // just toggle the button?
47750 if(btn.pressed !== this.sourceEditMode){
47751 btn.toggle(this.sourceEditMode);
47755 if(sourceEditMode){
47756 Roo.log("disabling buttons");
47757 this.tb.items.each(function(item){
47758 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
47764 Roo.log("enabling buttons");
47765 if(this.editorcore.initialized){
47766 this.tb.items.each(function(item){
47772 Roo.log("calling toggole on editor");
47773 // tell the editor that it's been pressed..
47774 this.editor.toggleSourceEdit(sourceEditMode);
47778 * Object collection of toolbar tooltips for the buttons in the editor. The key
47779 * is the command id associated with that button and the value is a valid QuickTips object.
47784 title: 'Bold (Ctrl+B)',
47785 text: 'Make the selected text bold.',
47786 cls: 'x-html-editor-tip'
47789 title: 'Italic (Ctrl+I)',
47790 text: 'Make the selected text italic.',
47791 cls: 'x-html-editor-tip'
47799 title: 'Bold (Ctrl+B)',
47800 text: 'Make the selected text bold.',
47801 cls: 'x-html-editor-tip'
47804 title: 'Italic (Ctrl+I)',
47805 text: 'Make the selected text italic.',
47806 cls: 'x-html-editor-tip'
47809 title: 'Underline (Ctrl+U)',
47810 text: 'Underline the selected text.',
47811 cls: 'x-html-editor-tip'
47814 title: 'Strikethrough',
47815 text: 'Strikethrough the selected text.',
47816 cls: 'x-html-editor-tip'
47818 increasefontsize : {
47819 title: 'Grow Text',
47820 text: 'Increase the font size.',
47821 cls: 'x-html-editor-tip'
47823 decreasefontsize : {
47824 title: 'Shrink Text',
47825 text: 'Decrease the font size.',
47826 cls: 'x-html-editor-tip'
47829 title: 'Text Highlight Color',
47830 text: 'Change the background color of the selected text.',
47831 cls: 'x-html-editor-tip'
47834 title: 'Font Color',
47835 text: 'Change the color of the selected text.',
47836 cls: 'x-html-editor-tip'
47839 title: 'Align Text Left',
47840 text: 'Align text to the left.',
47841 cls: 'x-html-editor-tip'
47844 title: 'Center Text',
47845 text: 'Center text in the editor.',
47846 cls: 'x-html-editor-tip'
47849 title: 'Align Text Right',
47850 text: 'Align text to the right.',
47851 cls: 'x-html-editor-tip'
47853 insertunorderedlist : {
47854 title: 'Bullet List',
47855 text: 'Start a bulleted list.',
47856 cls: 'x-html-editor-tip'
47858 insertorderedlist : {
47859 title: 'Numbered List',
47860 text: 'Start a numbered list.',
47861 cls: 'x-html-editor-tip'
47864 title: 'Hyperlink',
47865 text: 'Make the selected text a hyperlink.',
47866 cls: 'x-html-editor-tip'
47869 title: 'Source Edit',
47870 text: 'Switch to source editing mode.',
47871 cls: 'x-html-editor-tip'
47875 onDestroy : function(){
47878 this.tb.items.each(function(item){
47880 item.menu.removeAll();
47882 item.menu.el.destroy();
47890 onFirstFocus: function() {
47891 this.tb.items.each(function(item){
47900 // <script type="text/javascript">
47903 * Ext JS Library 1.1.1
47904 * Copyright(c) 2006-2007, Ext JS, LLC.
47911 * @class Roo.form.HtmlEditor.ToolbarContext
47916 new Roo.form.HtmlEditor({
47919 { xtype: 'ToolbarStandard', styles : {} }
47920 { xtype: 'ToolbarContext', disable : {} }
47926 * @config : {Object} disable List of elements to disable.. (not done yet.)
47927 * @config : {Object} styles Map of styles available.
47931 Roo.form.HtmlEditor.ToolbarContext = function(config)
47934 Roo.apply(this, config);
47935 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
47936 // dont call parent... till later.
47937 this.styles = this.styles || {};
47942 Roo.form.HtmlEditor.ToolbarContext.types = {
47954 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
47976 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
48028 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
48033 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
48043 style : 'fontFamily',
48044 displayField: 'display',
48045 optname : 'font-family',
48094 // should we really allow this??
48095 // should this just be
48106 style : 'fontFamily',
48107 displayField: 'display',
48108 optname : 'font-family',
48115 style : 'fontFamily',
48116 displayField: 'display',
48117 optname : 'font-family',
48124 style : 'fontFamily',
48125 displayField: 'display',
48126 optname : 'font-family',
48137 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
48138 Roo.form.HtmlEditor.ToolbarContext.stores = false;
48140 Roo.form.HtmlEditor.ToolbarContext.options = {
48142 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
48143 [ 'Courier New', 'Courier New'],
48144 [ 'Tahoma', 'Tahoma'],
48145 [ 'Times New Roman,serif', 'Times'],
48146 [ 'Verdana','Verdana' ]
48150 // fixme - these need to be configurable..
48153 //Roo.form.HtmlEditor.ToolbarContext.types
48156 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
48163 editorcore : false,
48165 * @cfg {Object} disable List of toolbar elements to disable
48170 * @cfg {Object} styles List of styles
48171 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
48173 * These must be defined in the page, so they get rendered correctly..
48184 init : function(editor)
48186 this.editor = editor;
48187 this.editorcore = editor.editorcore ? editor.editorcore : editor;
48188 var editorcore = this.editorcore;
48190 var fid = editorcore.frameId;
48192 function btn(id, toggle, handler){
48193 var xid = fid + '-'+ id ;
48197 cls : 'x-btn-icon x-edit-'+id,
48198 enableToggle:toggle !== false,
48199 scope: editorcore, // was editor...
48200 handler:handler||editorcore.relayBtnCmd,
48201 clickEvent:'mousedown',
48202 tooltip: etb.buttonTips[id] || undefined, ///tips ???
48206 // create a new element.
48207 var wdiv = editor.wrap.createChild({
48209 }, editor.wrap.dom.firstChild.nextSibling, true);
48211 // can we do this more than once??
48213 // stop form submits
48216 // disable everything...
48217 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
48218 this.toolbars = {};
48220 for (var i in ty) {
48222 this.toolbars[i] = this.buildToolbar(ty[i],i);
48224 this.tb = this.toolbars.BODY;
48226 this.buildFooter();
48227 this.footer.show();
48228 editor.on('hide', function( ) { this.footer.hide() }, this);
48229 editor.on('show', function( ) { this.footer.show() }, this);
48232 this.rendered = true;
48234 // the all the btns;
48235 editor.on('editorevent', this.updateToolbar, this);
48236 // other toolbars need to implement this..
48237 //editor.on('editmodechange', this.updateToolbar, this);
48243 * Protected method that will not generally be called directly. It triggers
48244 * a toolbar update by reading the markup state of the current selection in the editor.
48246 * Note you can force an update by calling on('editorevent', scope, false)
48248 updateToolbar: function(editor,ev,sel){
48251 // capture mouse up - this is handy for selecting images..
48252 // perhaps should go somewhere else...
48253 if(!this.editorcore.activated){
48254 this.editor.onFirstFocus();
48260 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
48261 // selectNode - might want to handle IE?
48263 (ev.type == 'mouseup' || ev.type == 'click' ) &&
48264 ev.target && ev.target.tagName == 'IMG') {
48265 // they have click on an image...
48266 // let's see if we can change the selection...
48269 var nodeRange = sel.ownerDocument.createRange();
48271 nodeRange.selectNode(sel);
48273 nodeRange.selectNodeContents(sel);
48275 //nodeRange.collapse(true);
48276 var s = this.editorcore.win.getSelection();
48277 s.removeAllRanges();
48278 s.addRange(nodeRange);
48282 var updateFooter = sel ? false : true;
48285 var ans = this.editorcore.getAllAncestors();
48288 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
48291 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
48292 sel = sel ? sel : this.editorcore.doc.body;
48293 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
48296 // pick a menu that exists..
48297 var tn = sel.tagName.toUpperCase();
48298 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
48300 tn = sel.tagName.toUpperCase();
48302 var lastSel = this.tb.selectedNode;
48304 this.tb.selectedNode = sel;
48306 // if current menu does not match..
48308 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
48311 ///console.log("show: " + tn);
48312 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
48315 this.tb.items.first().el.innerHTML = tn + ': ';
48318 // update attributes
48319 if (this.tb.fields) {
48320 this.tb.fields.each(function(e) {
48322 e.setValue(sel.style[e.stylename]);
48325 e.setValue(sel.getAttribute(e.attrname));
48329 var hasStyles = false;
48330 for(var i in this.styles) {
48337 var st = this.tb.fields.item(0);
48339 st.store.removeAll();
48342 var cn = sel.className.split(/\s+/);
48345 if (this.styles['*']) {
48347 Roo.each(this.styles['*'], function(v) {
48348 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
48351 if (this.styles[tn]) {
48352 Roo.each(this.styles[tn], function(v) {
48353 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
48357 st.store.loadData(avs);
48361 // flag our selected Node.
48362 this.tb.selectedNode = sel;
48365 Roo.menu.MenuMgr.hideAll();
48369 if (!updateFooter) {
48370 //this.footDisp.dom.innerHTML = '';
48373 // update the footer
48377 this.footerEls = ans.reverse();
48378 Roo.each(this.footerEls, function(a,i) {
48379 if (!a) { return; }
48380 html += html.length ? ' > ' : '';
48382 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
48387 var sz = this.footDisp.up('td').getSize();
48388 this.footDisp.dom.style.width = (sz.width -10) + 'px';
48389 this.footDisp.dom.style.marginLeft = '5px';
48391 this.footDisp.dom.style.overflow = 'hidden';
48393 this.footDisp.dom.innerHTML = html;
48395 //this.editorsyncValue();
48402 onDestroy : function(){
48405 this.tb.items.each(function(item){
48407 item.menu.removeAll();
48409 item.menu.el.destroy();
48417 onFirstFocus: function() {
48418 // need to do this for all the toolbars..
48419 this.tb.items.each(function(item){
48423 buildToolbar: function(tlist, nm)
48425 var editor = this.editor;
48426 var editorcore = this.editorcore;
48427 // create a new element.
48428 var wdiv = editor.wrap.createChild({
48430 }, editor.wrap.dom.firstChild.nextSibling, true);
48433 var tb = new Roo.Toolbar(wdiv);
48436 tb.add(nm+ ": ");
48439 for(var i in this.styles) {
48444 if (styles && styles.length) {
48446 // this needs a multi-select checkbox...
48447 tb.addField( new Roo.form.ComboBox({
48448 store: new Roo.data.SimpleStore({
48450 fields: ['val', 'selected'],
48453 name : '-roo-edit-className',
48454 attrname : 'className',
48455 displayField: 'val',
48459 triggerAction: 'all',
48460 emptyText:'Select Style',
48461 selectOnFocus:true,
48464 'select': function(c, r, i) {
48465 // initial support only for on class per el..
48466 tb.selectedNode.className = r ? r.get('val') : '';
48467 editorcore.syncValue();
48474 var tbc = Roo.form.HtmlEditor.ToolbarContext;
48475 var tbops = tbc.options;
48477 for (var i in tlist) {
48479 var item = tlist[i];
48480 tb.add(item.title + ": ");
48483 //optname == used so you can configure the options available..
48484 var opts = item.opts ? item.opts : false;
48485 if (item.optname) {
48486 opts = tbops[item.optname];
48491 // opts == pulldown..
48492 tb.addField( new Roo.form.ComboBox({
48493 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
48495 fields: ['val', 'display'],
48498 name : '-roo-edit-' + i,
48500 stylename : item.style ? item.style : false,
48501 displayField: item.displayField ? item.displayField : 'val',
48502 valueField : 'val',
48504 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
48506 triggerAction: 'all',
48507 emptyText:'Select',
48508 selectOnFocus:true,
48509 width: item.width ? item.width : 130,
48511 'select': function(c, r, i) {
48513 tb.selectedNode.style[c.stylename] = r.get('val');
48517 tb.selectedNode.removeAttribute(c.attrname);
48520 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
48529 tb.addField( new Roo.form.TextField({
48532 //allowBlank:false,
48537 tb.addField( new Roo.form.TextField({
48538 name: '-roo-edit-' + i,
48545 'change' : function(f, nv, ov) {
48546 tb.selectedNode.setAttribute(f.attrname, nv);
48547 editorcore.syncValue();
48560 text: 'Stylesheets',
48563 click : function ()
48565 _this.editor.fireEvent('stylesheetsclick', _this.editor);
48573 text: 'Remove Tag',
48576 click : function ()
48579 // undo does not work.
48581 var sn = tb.selectedNode;
48583 var pn = sn.parentNode;
48585 var stn = sn.childNodes[0];
48586 var en = sn.childNodes[sn.childNodes.length - 1 ];
48587 while (sn.childNodes.length) {
48588 var node = sn.childNodes[0];
48589 sn.removeChild(node);
48591 pn.insertBefore(node, sn);
48594 pn.removeChild(sn);
48595 var range = editorcore.createRange();
48597 range.setStart(stn,0);
48598 range.setEnd(en,0); //????
48599 //range.selectNode(sel);
48602 var selection = editorcore.getSelection();
48603 selection.removeAllRanges();
48604 selection.addRange(range);
48608 //_this.updateToolbar(null, null, pn);
48609 _this.updateToolbar(null, null, null);
48610 _this.footDisp.dom.innerHTML = '';
48620 tb.el.on('click', function(e){
48621 e.preventDefault(); // what does this do?
48623 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
48626 // dont need to disable them... as they will get hidden
48631 buildFooter : function()
48634 var fel = this.editor.wrap.createChild();
48635 this.footer = new Roo.Toolbar(fel);
48636 // toolbar has scrolly on left / right?
48637 var footDisp= new Roo.Toolbar.Fill();
48643 handler : function() {
48644 _t.footDisp.scrollTo('left',0,true)
48648 this.footer.add( footDisp );
48653 handler : function() {
48655 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
48659 var fel = Roo.get(footDisp.el);
48660 fel.addClass('x-editor-context');
48661 this.footDispWrap = fel;
48662 this.footDispWrap.overflow = 'hidden';
48664 this.footDisp = fel.createChild();
48665 this.footDispWrap.on('click', this.onContextClick, this)
48669 onContextClick : function (ev,dom)
48671 ev.preventDefault();
48672 var cn = dom.className;
48674 if (!cn.match(/x-ed-loc-/)) {
48677 var n = cn.split('-').pop();
48678 var ans = this.footerEls;
48682 var range = this.editorcore.createRange();
48684 range.selectNodeContents(sel);
48685 //range.selectNode(sel);
48688 var selection = this.editorcore.getSelection();
48689 selection.removeAllRanges();
48690 selection.addRange(range);
48694 this.updateToolbar(null, null, sel);
48711 * Ext JS Library 1.1.1
48712 * Copyright(c) 2006-2007, Ext JS, LLC.
48714 * Originally Released Under LGPL - original licence link has changed is not relivant.
48717 * <script type="text/javascript">
48721 * @class Roo.form.BasicForm
48722 * @extends Roo.util.Observable
48723 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
48725 * @param {String/HTMLElement/Roo.Element} el The form element or its id
48726 * @param {Object} config Configuration options
48728 Roo.form.BasicForm = function(el, config){
48729 this.allItems = [];
48730 this.childForms = [];
48731 Roo.apply(this, config);
48733 * The Roo.form.Field items in this form.
48734 * @type MixedCollection
48738 this.items = new Roo.util.MixedCollection(false, function(o){
48739 return o.id || (o.id = Roo.id());
48743 * @event beforeaction
48744 * Fires before any action is performed. Return false to cancel the action.
48745 * @param {Form} this
48746 * @param {Action} action The action to be performed
48748 beforeaction: true,
48750 * @event actionfailed
48751 * Fires when an action fails.
48752 * @param {Form} this
48753 * @param {Action} action The action that failed
48755 actionfailed : true,
48757 * @event actioncomplete
48758 * Fires when an action is completed.
48759 * @param {Form} this
48760 * @param {Action} action The action that completed
48762 actioncomplete : true
48767 Roo.form.BasicForm.superclass.constructor.call(this);
48769 Roo.form.BasicForm.popover.apply();
48772 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
48774 * @cfg {String} method
48775 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
48778 * @cfg {DataReader} reader
48779 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
48780 * This is optional as there is built-in support for processing JSON.
48783 * @cfg {DataReader} errorReader
48784 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
48785 * This is completely optional as there is built-in support for processing JSON.
48788 * @cfg {String} url
48789 * The URL to use for form actions if one isn't supplied in the action options.
48792 * @cfg {Boolean} fileUpload
48793 * Set to true if this form is a file upload.
48797 * @cfg {Object} baseParams
48798 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
48803 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
48808 activeAction : null,
48811 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
48812 * or setValues() data instead of when the form was first created.
48814 trackResetOnLoad : false,
48818 * childForms - used for multi-tab forms
48821 childForms : false,
48824 * allItems - full list of fields.
48830 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
48831 * element by passing it or its id or mask the form itself by passing in true.
48834 waitMsgTarget : false,
48839 disableMask : false,
48842 * @cfg {Boolean} errorMask (true|false) default false
48847 * @cfg {Number} maskOffset Default 100
48852 initEl : function(el){
48853 this.el = Roo.get(el);
48854 this.id = this.el.id || Roo.id();
48855 this.el.on('submit', this.onSubmit, this);
48856 this.el.addClass('x-form');
48860 onSubmit : function(e){
48865 * Returns true if client-side validation on the form is successful.
48868 isValid : function(){
48870 var target = false;
48871 this.items.each(function(f){
48878 if(!target && f.el.isVisible(true)){
48883 if(this.errorMask && !valid){
48884 Roo.form.BasicForm.popover.mask(this, target);
48890 * Returns array of invalid form fields.
48894 invalidFields : function()
48897 this.items.each(function(f){
48910 * DEPRICATED Returns true if any fields in this form have changed since their original load.
48913 isDirty : function(){
48915 this.items.each(function(f){
48925 * Returns true if any fields in this form have changed since their original load. (New version)
48929 hasChanged : function()
48932 this.items.each(function(f){
48933 if(f.hasChanged()){
48942 * Resets all hasChanged to 'false' -
48943 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
48944 * So hasChanged storage is only to be used for this purpose
48947 resetHasChanged : function()
48949 this.items.each(function(f){
48950 f.resetHasChanged();
48957 * Performs a predefined action (submit or load) or custom actions you define on this form.
48958 * @param {String} actionName The name of the action type
48959 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
48960 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
48961 * accept other config options):
48963 Property Type Description
48964 ---------------- --------------- ----------------------------------------------------------------------------------
48965 url String The url for the action (defaults to the form's url)
48966 method String The form method to use (defaults to the form's method, or POST if not defined)
48967 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
48968 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
48969 validate the form on the client (defaults to false)
48971 * @return {BasicForm} this
48973 doAction : function(action, options){
48974 if(typeof action == 'string'){
48975 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
48977 if(this.fireEvent('beforeaction', this, action) !== false){
48978 this.beforeAction(action);
48979 action.run.defer(100, action);
48985 * Shortcut to do a submit action.
48986 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
48987 * @return {BasicForm} this
48989 submit : function(options){
48990 this.doAction('submit', options);
48995 * Shortcut to do a load action.
48996 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
48997 * @return {BasicForm} this
48999 load : function(options){
49000 this.doAction('load', options);
49005 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
49006 * @param {Record} record The record to edit
49007 * @return {BasicForm} this
49009 updateRecord : function(record){
49010 record.beginEdit();
49011 var fs = record.fields;
49012 fs.each(function(f){
49013 var field = this.findField(f.name);
49015 record.set(f.name, field.getValue());
49023 * Loads an Roo.data.Record into this form.
49024 * @param {Record} record The record to load
49025 * @return {BasicForm} this
49027 loadRecord : function(record){
49028 this.setValues(record.data);
49033 beforeAction : function(action){
49034 var o = action.options;
49036 if(!this.disableMask) {
49037 if(this.waitMsgTarget === true){
49038 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
49039 }else if(this.waitMsgTarget){
49040 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
49041 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
49043 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
49051 afterAction : function(action, success){
49052 this.activeAction = null;
49053 var o = action.options;
49055 if(!this.disableMask) {
49056 if(this.waitMsgTarget === true){
49058 }else if(this.waitMsgTarget){
49059 this.waitMsgTarget.unmask();
49061 Roo.MessageBox.updateProgress(1);
49062 Roo.MessageBox.hide();
49070 Roo.callback(o.success, o.scope, [this, action]);
49071 this.fireEvent('actioncomplete', this, action);
49075 // failure condition..
49076 // we have a scenario where updates need confirming.
49077 // eg. if a locking scenario exists..
49078 // we look for { errors : { needs_confirm : true }} in the response.
49080 (typeof(action.result) != 'undefined') &&
49081 (typeof(action.result.errors) != 'undefined') &&
49082 (typeof(action.result.errors.needs_confirm) != 'undefined')
49085 Roo.MessageBox.confirm(
49086 "Change requires confirmation",
49087 action.result.errorMsg,
49092 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
49102 Roo.callback(o.failure, o.scope, [this, action]);
49103 // show an error message if no failed handler is set..
49104 if (!this.hasListener('actionfailed')) {
49105 Roo.MessageBox.alert("Error",
49106 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
49107 action.result.errorMsg :
49108 "Saving Failed, please check your entries or try again"
49112 this.fireEvent('actionfailed', this, action);
49118 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
49119 * @param {String} id The value to search for
49122 findField : function(id){
49123 var field = this.items.get(id);
49125 this.items.each(function(f){
49126 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
49132 return field || null;
49136 * Add a secondary form to this one,
49137 * Used to provide tabbed forms. One form is primary, with hidden values
49138 * which mirror the elements from the other forms.
49140 * @param {Roo.form.Form} form to add.
49143 addForm : function(form)
49146 if (this.childForms.indexOf(form) > -1) {
49150 this.childForms.push(form);
49152 Roo.each(form.allItems, function (fe) {
49154 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
49155 if (this.findField(n)) { // already added..
49158 var add = new Roo.form.Hidden({
49161 add.render(this.el);
49168 * Mark fields in this form invalid in bulk.
49169 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
49170 * @return {BasicForm} this
49172 markInvalid : function(errors){
49173 if(errors instanceof Array){
49174 for(var i = 0, len = errors.length; i < len; i++){
49175 var fieldError = errors[i];
49176 var f = this.findField(fieldError.id);
49178 f.markInvalid(fieldError.msg);
49184 if(typeof errors[id] != 'function' && (field = this.findField(id))){
49185 field.markInvalid(errors[id]);
49189 Roo.each(this.childForms || [], function (f) {
49190 f.markInvalid(errors);
49197 * Set values for fields in this form in bulk.
49198 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
49199 * @return {BasicForm} this
49201 setValues : function(values){
49202 if(values instanceof Array){ // array of objects
49203 for(var i = 0, len = values.length; i < len; i++){
49205 var f = this.findField(v.id);
49207 f.setValue(v.value);
49208 if(this.trackResetOnLoad){
49209 f.originalValue = f.getValue();
49213 }else{ // object hash
49216 if(typeof values[id] != 'function' && (field = this.findField(id))){
49218 if (field.setFromData &&
49219 field.valueField &&
49220 field.displayField &&
49221 // combos' with local stores can
49222 // be queried via setValue()
49223 // to set their value..
49224 (field.store && !field.store.isLocal)
49228 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
49229 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
49230 field.setFromData(sd);
49233 field.setValue(values[id]);
49237 if(this.trackResetOnLoad){
49238 field.originalValue = field.getValue();
49243 this.resetHasChanged();
49246 Roo.each(this.childForms || [], function (f) {
49247 f.setValues(values);
49248 f.resetHasChanged();
49255 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
49256 * they are returned as an array.
49257 * @param {Boolean} asString
49260 getValues : function(asString){
49261 if (this.childForms) {
49262 // copy values from the child forms
49263 Roo.each(this.childForms, function (f) {
49264 this.setValues(f.getValues());
49269 if (typeof(FormData) != 'undefined' && asString !== true) {
49270 // this relies on a 'recent' version of chrome apparently...
49272 var fd = (new FormData(this.el.dom)).entries();
49274 var ent = fd.next();
49275 while (!ent.done) {
49276 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
49287 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
49288 if(asString === true){
49291 return Roo.urlDecode(fs);
49295 * Returns the fields in this form as an object with key/value pairs.
49296 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
49299 getFieldValues : function(with_hidden)
49301 if (this.childForms) {
49302 // copy values from the child forms
49303 // should this call getFieldValues - probably not as we do not currently copy
49304 // hidden fields when we generate..
49305 Roo.each(this.childForms, function (f) {
49306 this.setValues(f.getValues());
49311 this.items.each(function(f){
49312 if (!f.getName()) {
49315 var v = f.getValue();
49316 if (f.inputType =='radio') {
49317 if (typeof(ret[f.getName()]) == 'undefined') {
49318 ret[f.getName()] = ''; // empty..
49321 if (!f.el.dom.checked) {
49325 v = f.el.dom.value;
49329 // not sure if this supported any more..
49330 if ((typeof(v) == 'object') && f.getRawValue) {
49331 v = f.getRawValue() ; // dates..
49333 // combo boxes where name != hiddenName...
49334 if (f.name != f.getName()) {
49335 ret[f.name] = f.getRawValue();
49337 ret[f.getName()] = v;
49344 * Clears all invalid messages in this form.
49345 * @return {BasicForm} this
49347 clearInvalid : function(){
49348 this.items.each(function(f){
49352 Roo.each(this.childForms || [], function (f) {
49361 * Resets this form.
49362 * @return {BasicForm} this
49364 reset : function(){
49365 this.items.each(function(f){
49369 Roo.each(this.childForms || [], function (f) {
49372 this.resetHasChanged();
49378 * Add Roo.form components to this form.
49379 * @param {Field} field1
49380 * @param {Field} field2 (optional)
49381 * @param {Field} etc (optional)
49382 * @return {BasicForm} this
49385 this.items.addAll(Array.prototype.slice.call(arguments, 0));
49391 * Removes a field from the items collection (does NOT remove its markup).
49392 * @param {Field} field
49393 * @return {BasicForm} this
49395 remove : function(field){
49396 this.items.remove(field);
49401 * Looks at the fields in this form, checks them for an id attribute,
49402 * and calls applyTo on the existing dom element with that id.
49403 * @return {BasicForm} this
49405 render : function(){
49406 this.items.each(function(f){
49407 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
49415 * Calls {@link Ext#apply} for all fields in this form with the passed object.
49416 * @param {Object} values
49417 * @return {BasicForm} this
49419 applyToFields : function(o){
49420 this.items.each(function(f){
49427 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
49428 * @param {Object} values
49429 * @return {BasicForm} this
49431 applyIfToFields : function(o){
49432 this.items.each(function(f){
49440 Roo.BasicForm = Roo.form.BasicForm;
49442 Roo.apply(Roo.form.BasicForm, {
49456 intervalID : false,
49462 if(this.isApplied){
49467 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
49468 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
49469 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
49470 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
49473 this.maskEl.top.enableDisplayMode("block");
49474 this.maskEl.left.enableDisplayMode("block");
49475 this.maskEl.bottom.enableDisplayMode("block");
49476 this.maskEl.right.enableDisplayMode("block");
49478 Roo.get(document.body).on('click', function(){
49482 Roo.get(document.body).on('touchstart', function(){
49486 this.isApplied = true
49489 mask : function(form, target)
49493 this.target = target;
49495 if(!this.form.errorMask || !target.el){
49499 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
49501 var ot = this.target.el.calcOffsetsTo(scrollable);
49503 var scrollTo = ot[1] - this.form.maskOffset;
49505 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
49507 scrollable.scrollTo('top', scrollTo);
49509 var el = this.target.wrap || this.target.el;
49511 var box = el.getBox();
49513 this.maskEl.top.setStyle('position', 'absolute');
49514 this.maskEl.top.setStyle('z-index', 10000);
49515 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
49516 this.maskEl.top.setLeft(0);
49517 this.maskEl.top.setTop(0);
49518 this.maskEl.top.show();
49520 this.maskEl.left.setStyle('position', 'absolute');
49521 this.maskEl.left.setStyle('z-index', 10000);
49522 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
49523 this.maskEl.left.setLeft(0);
49524 this.maskEl.left.setTop(box.y - this.padding);
49525 this.maskEl.left.show();
49527 this.maskEl.bottom.setStyle('position', 'absolute');
49528 this.maskEl.bottom.setStyle('z-index', 10000);
49529 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
49530 this.maskEl.bottom.setLeft(0);
49531 this.maskEl.bottom.setTop(box.bottom + this.padding);
49532 this.maskEl.bottom.show();
49534 this.maskEl.right.setStyle('position', 'absolute');
49535 this.maskEl.right.setStyle('z-index', 10000);
49536 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
49537 this.maskEl.right.setLeft(box.right + this.padding);
49538 this.maskEl.right.setTop(box.y - this.padding);
49539 this.maskEl.right.show();
49541 this.intervalID = window.setInterval(function() {
49542 Roo.form.BasicForm.popover.unmask();
49545 window.onwheel = function(){ return false;};
49547 (function(){ this.isMasked = true; }).defer(500, this);
49551 unmask : function()
49553 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
49557 this.maskEl.top.setStyle('position', 'absolute');
49558 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
49559 this.maskEl.top.hide();
49561 this.maskEl.left.setStyle('position', 'absolute');
49562 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
49563 this.maskEl.left.hide();
49565 this.maskEl.bottom.setStyle('position', 'absolute');
49566 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
49567 this.maskEl.bottom.hide();
49569 this.maskEl.right.setStyle('position', 'absolute');
49570 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
49571 this.maskEl.right.hide();
49573 window.onwheel = function(){ return true;};
49575 if(this.intervalID){
49576 window.clearInterval(this.intervalID);
49577 this.intervalID = false;
49580 this.isMasked = false;
49588 * Ext JS Library 1.1.1
49589 * Copyright(c) 2006-2007, Ext JS, LLC.
49591 * Originally Released Under LGPL - original licence link has changed is not relivant.
49594 * <script type="text/javascript">
49598 * @class Roo.form.Form
49599 * @extends Roo.form.BasicForm
49600 * @children Roo.form.Column Roo.form.FieldSet Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49601 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
49603 * @param {Object} config Configuration options
49605 Roo.form.Form = function(config){
49607 if (config.items) {
49608 xitems = config.items;
49609 delete config.items;
49613 Roo.form.Form.superclass.constructor.call(this, null, config);
49614 this.url = this.url || this.action;
49616 this.root = new Roo.form.Layout(Roo.applyIf({
49620 this.active = this.root;
49622 * Array of all the buttons that have been added to this form via {@link addButton}
49626 this.allItems = [];
49629 * @event clientvalidation
49630 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
49631 * @param {Form} this
49632 * @param {Boolean} valid true if the form has passed client-side validation
49634 clientvalidation: true,
49637 * Fires when the form is rendered
49638 * @param {Roo.form.Form} form
49643 if (this.progressUrl) {
49644 // push a hidden field onto the list of fields..
49648 name : 'UPLOAD_IDENTIFIER'
49653 Roo.each(xitems, this.addxtype, this);
49657 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
49659 * @cfg {Roo.Button} buttons[] buttons at bottom of form
49663 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
49666 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
49669 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
49671 buttonAlign:'center',
49674 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
49679 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
49680 * This property cascades to child containers if not set.
49685 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
49686 * fires a looping event with that state. This is required to bind buttons to the valid
49687 * state using the config value formBind:true on the button.
49689 monitorValid : false,
49692 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
49697 * @cfg {String} progressUrl - Url to return progress data
49700 progressUrl : false,
49702 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
49703 * sending a formdata with extra parameters - eg uploaded elements.
49709 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
49710 * fields are added and the column is closed. If no fields are passed the column remains open
49711 * until end() is called.
49712 * @param {Object} config The config to pass to the column
49713 * @param {Field} field1 (optional)
49714 * @param {Field} field2 (optional)
49715 * @param {Field} etc (optional)
49716 * @return Column The column container object
49718 column : function(c){
49719 var col = new Roo.form.Column(c);
49721 if(arguments.length > 1){ // duplicate code required because of Opera
49722 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
49729 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
49730 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
49731 * until end() is called.
49732 * @param {Object} config The config to pass to the fieldset
49733 * @param {Field} field1 (optional)
49734 * @param {Field} field2 (optional)
49735 * @param {Field} etc (optional)
49736 * @return FieldSet The fieldset container object
49738 fieldset : function(c){
49739 var fs = new Roo.form.FieldSet(c);
49741 if(arguments.length > 1){ // duplicate code required because of Opera
49742 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
49749 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
49750 * fields are added and the container is closed. If no fields are passed the container remains open
49751 * until end() is called.
49752 * @param {Object} config The config to pass to the Layout
49753 * @param {Field} field1 (optional)
49754 * @param {Field} field2 (optional)
49755 * @param {Field} etc (optional)
49756 * @return Layout The container object
49758 container : function(c){
49759 var l = new Roo.form.Layout(c);
49761 if(arguments.length > 1){ // duplicate code required because of Opera
49762 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
49769 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
49770 * @param {Object} container A Roo.form.Layout or subclass of Layout
49771 * @return {Form} this
49773 start : function(c){
49774 // cascade label info
49775 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
49776 this.active.stack.push(c);
49777 c.ownerCt = this.active;
49783 * Closes the current open container
49784 * @return {Form} this
49787 if(this.active == this.root){
49790 this.active = this.active.ownerCt;
49795 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
49796 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
49797 * as the label of the field.
49798 * @param {Field} field1
49799 * @param {Field} field2 (optional)
49800 * @param {Field} etc. (optional)
49801 * @return {Form} this
49804 this.active.stack.push.apply(this.active.stack, arguments);
49805 this.allItems.push.apply(this.allItems,arguments);
49807 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
49808 if(a[i].isFormField){
49813 Roo.form.Form.superclass.add.apply(this, r);
49823 * Find any element that has been added to a form, using it's ID or name
49824 * This can include framesets, columns etc. along with regular fields..
49825 * @param {String} id - id or name to find.
49827 * @return {Element} e - or false if nothing found.
49829 findbyId : function(id)
49835 Roo.each(this.allItems, function(f){
49836 if (f.id == id || f.name == id ){
49847 * Render this form into the passed container. This should only be called once!
49848 * @param {String/HTMLElement/Element} container The element this component should be rendered into
49849 * @return {Form} this
49851 render : function(ct)
49857 var o = this.autoCreate || {
49859 method : this.method || 'POST',
49860 id : this.id || Roo.id()
49862 this.initEl(ct.createChild(o));
49864 this.root.render(this.el);
49868 this.items.each(function(f){
49869 f.render('x-form-el-'+f.id);
49872 if(this.buttons.length > 0){
49873 // tables are required to maintain order and for correct IE layout
49874 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
49875 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
49876 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
49878 var tr = tb.getElementsByTagName('tr')[0];
49879 for(var i = 0, len = this.buttons.length; i < len; i++) {
49880 var b = this.buttons[i];
49881 var td = document.createElement('td');
49882 td.className = 'x-form-btn-td';
49883 b.render(tr.appendChild(td));
49886 if(this.monitorValid){ // initialize after render
49887 this.startMonitoring();
49889 this.fireEvent('rendered', this);
49894 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
49895 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
49896 * object or a valid Roo.DomHelper element config
49897 * @param {Function} handler The function called when the button is clicked
49898 * @param {Object} scope (optional) The scope of the handler function
49899 * @return {Roo.Button}
49901 addButton : function(config, handler, scope){
49905 minWidth: this.minButtonWidth,
49908 if(typeof config == "string"){
49911 Roo.apply(bc, config);
49913 var btn = new Roo.Button(null, bc);
49914 this.buttons.push(btn);
49919 * Adds a series of form elements (using the xtype property as the factory method.
49920 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
49921 * @param {Object} config
49924 addxtype : function()
49926 var ar = Array.prototype.slice.call(arguments, 0);
49928 for(var i = 0; i < ar.length; i++) {
49930 continue; // skip -- if this happends something invalid got sent, we
49931 // should ignore it, as basically that interface element will not show up
49932 // and that should be pretty obvious!!
49935 if (Roo.form[ar[i].xtype]) {
49937 var fe = Roo.factory(ar[i], Roo.form);
49943 fe.store.form = this;
49948 this.allItems.push(fe);
49949 if (fe.items && fe.addxtype) {
49950 fe.addxtype.apply(fe, fe.items);
49960 // console.log('adding ' + ar[i].xtype);
49962 if (ar[i].xtype == 'Button') {
49963 //console.log('adding button');
49964 //console.log(ar[i]);
49965 this.addButton(ar[i]);
49966 this.allItems.push(fe);
49970 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
49971 alert('end is not supported on xtype any more, use items');
49973 // //console.log('adding end');
49981 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
49982 * option "monitorValid"
49984 startMonitoring : function(){
49987 Roo.TaskMgr.start({
49988 run : this.bindHandler,
49989 interval : this.monitorPoll || 200,
49996 * Stops monitoring of the valid state of this form
49998 stopMonitoring : function(){
49999 this.bound = false;
50003 bindHandler : function(){
50005 return false; // stops binding
50008 this.items.each(function(f){
50009 if(!f.isValid(true)){
50014 for(var i = 0, len = this.buttons.length; i < len; i++){
50015 var btn = this.buttons[i];
50016 if(btn.formBind === true && btn.disabled === valid){
50017 btn.setDisabled(!valid);
50020 this.fireEvent('clientvalidation', this, valid);
50034 Roo.Form = Roo.form.Form;
50037 * Ext JS Library 1.1.1
50038 * Copyright(c) 2006-2007, Ext JS, LLC.
50040 * Originally Released Under LGPL - original licence link has changed is not relivant.
50043 * <script type="text/javascript">
50046 // as we use this in bootstrap.
50047 Roo.namespace('Roo.form');
50049 * @class Roo.form.Action
50050 * Internal Class used to handle form actions
50052 * @param {Roo.form.BasicForm} el The form element or its id
50053 * @param {Object} config Configuration options
50058 // define the action interface
50059 Roo.form.Action = function(form, options){
50061 this.options = options || {};
50064 * Client Validation Failed
50067 Roo.form.Action.CLIENT_INVALID = 'client';
50069 * Server Validation Failed
50072 Roo.form.Action.SERVER_INVALID = 'server';
50074 * Connect to Server Failed
50077 Roo.form.Action.CONNECT_FAILURE = 'connect';
50079 * Reading Data from Server Failed
50082 Roo.form.Action.LOAD_FAILURE = 'load';
50084 Roo.form.Action.prototype = {
50086 failureType : undefined,
50087 response : undefined,
50088 result : undefined,
50090 // interface method
50091 run : function(options){
50095 // interface method
50096 success : function(response){
50100 // interface method
50101 handleResponse : function(response){
50105 // default connection failure
50106 failure : function(response){
50108 this.response = response;
50109 this.failureType = Roo.form.Action.CONNECT_FAILURE;
50110 this.form.afterAction(this, false);
50113 processResponse : function(response){
50114 this.response = response;
50115 if(!response.responseText){
50118 this.result = this.handleResponse(response);
50119 return this.result;
50122 // utility functions used internally
50123 getUrl : function(appendParams){
50124 var url = this.options.url || this.form.url || this.form.el.dom.action;
50126 var p = this.getParams();
50128 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
50134 getMethod : function(){
50135 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
50138 getParams : function(){
50139 var bp = this.form.baseParams;
50140 var p = this.options.params;
50142 if(typeof p == "object"){
50143 p = Roo.urlEncode(Roo.applyIf(p, bp));
50144 }else if(typeof p == 'string' && bp){
50145 p += '&' + Roo.urlEncode(bp);
50148 p = Roo.urlEncode(bp);
50153 createCallback : function(){
50155 success: this.success,
50156 failure: this.failure,
50158 timeout: (this.form.timeout*1000),
50159 upload: this.form.fileUpload ? this.success : undefined
50164 Roo.form.Action.Submit = function(form, options){
50165 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
50168 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
50171 haveProgress : false,
50172 uploadComplete : false,
50174 // uploadProgress indicator.
50175 uploadProgress : function()
50177 if (!this.form.progressUrl) {
50181 if (!this.haveProgress) {
50182 Roo.MessageBox.progress("Uploading", "Uploading");
50184 if (this.uploadComplete) {
50185 Roo.MessageBox.hide();
50189 this.haveProgress = true;
50191 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
50193 var c = new Roo.data.Connection();
50195 url : this.form.progressUrl,
50200 success : function(req){
50201 //console.log(data);
50205 rdata = Roo.decode(req.responseText)
50207 Roo.log("Invalid data from server..");
50211 if (!rdata || !rdata.success) {
50213 Roo.MessageBox.alert(Roo.encode(rdata));
50216 var data = rdata.data;
50218 if (this.uploadComplete) {
50219 Roo.MessageBox.hide();
50224 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
50225 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
50228 this.uploadProgress.defer(2000,this);
50231 failure: function(data) {
50232 Roo.log('progress url failed ');
50243 // run get Values on the form, so it syncs any secondary forms.
50244 this.form.getValues();
50246 var o = this.options;
50247 var method = this.getMethod();
50248 var isPost = method == 'POST';
50249 if(o.clientValidation === false || this.form.isValid()){
50251 if (this.form.progressUrl) {
50252 this.form.findField('UPLOAD_IDENTIFIER').setValue(
50253 (new Date() * 1) + '' + Math.random());
50258 Roo.Ajax.request(Roo.apply(this.createCallback(), {
50259 form:this.form.el.dom,
50260 url:this.getUrl(!isPost),
50262 params:isPost ? this.getParams() : null,
50263 isUpload: this.form.fileUpload,
50264 formData : this.form.formData
50267 this.uploadProgress();
50269 }else if (o.clientValidation !== false){ // client validation failed
50270 this.failureType = Roo.form.Action.CLIENT_INVALID;
50271 this.form.afterAction(this, false);
50275 success : function(response)
50277 this.uploadComplete= true;
50278 if (this.haveProgress) {
50279 Roo.MessageBox.hide();
50283 var result = this.processResponse(response);
50284 if(result === true || result.success){
50285 this.form.afterAction(this, true);
50289 this.form.markInvalid(result.errors);
50290 this.failureType = Roo.form.Action.SERVER_INVALID;
50292 this.form.afterAction(this, false);
50294 failure : function(response)
50296 this.uploadComplete= true;
50297 if (this.haveProgress) {
50298 Roo.MessageBox.hide();
50301 this.response = response;
50302 this.failureType = Roo.form.Action.CONNECT_FAILURE;
50303 this.form.afterAction(this, false);
50306 handleResponse : function(response){
50307 if(this.form.errorReader){
50308 var rs = this.form.errorReader.read(response);
50311 for(var i = 0, len = rs.records.length; i < len; i++) {
50312 var r = rs.records[i];
50313 errors[i] = r.data;
50316 if(errors.length < 1){
50320 success : rs.success,
50326 ret = Roo.decode(response.responseText);
50330 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
50340 Roo.form.Action.Load = function(form, options){
50341 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
50342 this.reader = this.form.reader;
50345 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
50350 Roo.Ajax.request(Roo.apply(
50351 this.createCallback(), {
50352 method:this.getMethod(),
50353 url:this.getUrl(false),
50354 params:this.getParams()
50358 success : function(response){
50360 var result = this.processResponse(response);
50361 if(result === true || !result.success || !result.data){
50362 this.failureType = Roo.form.Action.LOAD_FAILURE;
50363 this.form.afterAction(this, false);
50366 this.form.clearInvalid();
50367 this.form.setValues(result.data);
50368 this.form.afterAction(this, true);
50371 handleResponse : function(response){
50372 if(this.form.reader){
50373 var rs = this.form.reader.read(response);
50374 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
50376 success : rs.success,
50380 return Roo.decode(response.responseText);
50384 Roo.form.Action.ACTION_TYPES = {
50385 'load' : Roo.form.Action.Load,
50386 'submit' : Roo.form.Action.Submit
50389 * Ext JS Library 1.1.1
50390 * Copyright(c) 2006-2007, Ext JS, LLC.
50392 * Originally Released Under LGPL - original licence link has changed is not relivant.
50395 * <script type="text/javascript">
50399 * @class Roo.form.Layout
50400 * @extends Roo.Component
50401 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
50402 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
50404 * @param {Object} config Configuration options
50406 Roo.form.Layout = function(config){
50408 if (config.items) {
50409 xitems = config.items;
50410 delete config.items;
50412 Roo.form.Layout.superclass.constructor.call(this, config);
50414 Roo.each(xitems, this.addxtype, this);
50418 Roo.extend(Roo.form.Layout, Roo.Component, {
50420 * @cfg {String/Object} autoCreate
50421 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
50424 * @cfg {String/Object/Function} style
50425 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
50426 * a function which returns such a specification.
50429 * @cfg {String} labelAlign
50430 * Valid values are "left," "top" and "right" (defaults to "left")
50433 * @cfg {Number} labelWidth
50434 * Fixed width in pixels of all field labels (defaults to undefined)
50437 * @cfg {Boolean} clear
50438 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
50442 * @cfg {String} labelSeparator
50443 * The separator to use after field labels (defaults to ':')
50445 labelSeparator : ':',
50447 * @cfg {Boolean} hideLabels
50448 * True to suppress the display of field labels in this layout (defaults to false)
50450 hideLabels : false,
50453 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
50458 onRender : function(ct, position){
50459 if(this.el){ // from markup
50460 this.el = Roo.get(this.el);
50461 }else { // generate
50462 var cfg = this.getAutoCreate();
50463 this.el = ct.createChild(cfg, position);
50466 this.el.applyStyles(this.style);
50468 if(this.labelAlign){
50469 this.el.addClass('x-form-label-'+this.labelAlign);
50471 if(this.hideLabels){
50472 this.labelStyle = "display:none";
50473 this.elementStyle = "padding-left:0;";
50475 if(typeof this.labelWidth == 'number'){
50476 this.labelStyle = "width:"+this.labelWidth+"px;";
50477 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
50479 if(this.labelAlign == 'top'){
50480 this.labelStyle = "width:auto;";
50481 this.elementStyle = "padding-left:0;";
50484 var stack = this.stack;
50485 var slen = stack.length;
50487 if(!this.fieldTpl){
50488 var t = new Roo.Template(
50489 '<div class="x-form-item {5}">',
50490 '<label for="{0}" style="{2}">{1}{4}</label>',
50491 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
50493 '</div><div class="x-form-clear-left"></div>'
50495 t.disableFormats = true;
50497 Roo.form.Layout.prototype.fieldTpl = t;
50499 for(var i = 0; i < slen; i++) {
50500 if(stack[i].isFormField){
50501 this.renderField(stack[i]);
50503 this.renderComponent(stack[i]);
50508 this.el.createChild({cls:'x-form-clear'});
50513 renderField : function(f){
50514 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
50517 f.labelStyle||this.labelStyle||'', //2
50518 this.elementStyle||'', //3
50519 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
50520 f.itemCls||this.itemCls||'' //5
50521 ], true).getPrevSibling());
50525 renderComponent : function(c){
50526 c.render(c.isLayout ? this.el : this.el.createChild());
50529 * Adds a object form elements (using the xtype property as the factory method.)
50530 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
50531 * @param {Object} config
50533 addxtype : function(o)
50535 // create the lement.
50536 o.form = this.form;
50537 var fe = Roo.factory(o, Roo.form);
50538 this.form.allItems.push(fe);
50539 this.stack.push(fe);
50541 if (fe.isFormField) {
50542 this.form.items.add(fe);
50550 * @class Roo.form.Column
50551 * @extends Roo.form.Layout
50552 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
50554 * @param {Object} config Configuration options
50556 Roo.form.Column = function(config){
50557 Roo.form.Column.superclass.constructor.call(this, config);
50560 Roo.extend(Roo.form.Column, Roo.form.Layout, {
50562 * @cfg {Number/String} width
50563 * The fixed width of the column in pixels or CSS value (defaults to "auto")
50566 * @cfg {String/Object} autoCreate
50567 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
50571 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
50574 onRender : function(ct, position){
50575 Roo.form.Column.superclass.onRender.call(this, ct, position);
50577 this.el.setWidth(this.width);
50584 * @class Roo.form.Row
50585 * @extends Roo.form.Layout
50586 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
50587 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
50589 * @param {Object} config Configuration options
50593 Roo.form.Row = function(config){
50594 Roo.form.Row.superclass.constructor.call(this, config);
50597 Roo.extend(Roo.form.Row, Roo.form.Layout, {
50599 * @cfg {Number/String} width
50600 * The fixed width of the column in pixels or CSS value (defaults to "auto")
50603 * @cfg {Number/String} height
50604 * The fixed height of the column in pixels or CSS value (defaults to "auto")
50606 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
50610 onRender : function(ct, position){
50611 //console.log('row render');
50613 var t = new Roo.Template(
50614 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
50615 '<label for="{0}" style="{2}">{1}{4}</label>',
50616 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
50620 t.disableFormats = true;
50622 Roo.form.Layout.prototype.rowTpl = t;
50624 this.fieldTpl = this.rowTpl;
50626 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
50627 var labelWidth = 100;
50629 if ((this.labelAlign != 'top')) {
50630 if (typeof this.labelWidth == 'number') {
50631 labelWidth = this.labelWidth
50633 this.padWidth = 20 + labelWidth;
50637 Roo.form.Column.superclass.onRender.call(this, ct, position);
50639 this.el.setWidth(this.width);
50642 this.el.setHeight(this.height);
50647 renderField : function(f){
50648 f.fieldEl = this.fieldTpl.append(this.el, [
50649 f.id, f.fieldLabel,
50650 f.labelStyle||this.labelStyle||'',
50651 this.elementStyle||'',
50652 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
50653 f.itemCls||this.itemCls||'',
50654 f.width ? f.width + this.padWidth : 160 + this.padWidth
50661 * @class Roo.form.FieldSet
50662 * @extends Roo.form.Layout
50663 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
50664 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
50666 * @param {Object} config Configuration options
50668 Roo.form.FieldSet = function(config){
50669 Roo.form.FieldSet.superclass.constructor.call(this, config);
50672 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
50674 * @cfg {String} legend
50675 * The text to display as the legend for the FieldSet (defaults to '')
50678 * @cfg {String/Object} autoCreate
50679 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
50683 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
50686 onRender : function(ct, position){
50687 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
50689 this.setLegend(this.legend);
50694 setLegend : function(text){
50696 this.el.child('legend').update(text);
50701 * Ext JS Library 1.1.1
50702 * Copyright(c) 2006-2007, Ext JS, LLC.
50704 * Originally Released Under LGPL - original licence link has changed is not relivant.
50707 * <script type="text/javascript">
50710 * @class Roo.form.VTypes
50711 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
50714 Roo.form.VTypes = function(){
50715 // closure these in so they are only created once.
50716 var alpha = /^[a-zA-Z_]+$/;
50717 var alphanum = /^[a-zA-Z0-9_]+$/;
50718 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
50719 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
50721 // All these messages and functions are configurable
50724 * The function used to validate email addresses
50725 * @param {String} value The email address
50727 'email' : function(v){
50728 return email.test(v);
50731 * The error text to display when the email validation function returns false
50734 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
50736 * The keystroke filter mask to be applied on email input
50739 'emailMask' : /[a-z0-9_\.\-@]/i,
50742 * The function used to validate URLs
50743 * @param {String} value The URL
50745 'url' : function(v){
50746 return url.test(v);
50749 * The error text to display when the url validation function returns false
50752 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
50755 * The function used to validate alpha values
50756 * @param {String} value The value
50758 'alpha' : function(v){
50759 return alpha.test(v);
50762 * The error text to display when the alpha validation function returns false
50765 'alphaText' : 'This field should only contain letters and _',
50767 * The keystroke filter mask to be applied on alpha input
50770 'alphaMask' : /[a-z_]/i,
50773 * The function used to validate alphanumeric values
50774 * @param {String} value The value
50776 'alphanum' : function(v){
50777 return alphanum.test(v);
50780 * The error text to display when the alphanumeric validation function returns false
50783 'alphanumText' : 'This field should only contain letters, numbers and _',
50785 * The keystroke filter mask to be applied on alphanumeric input
50788 'alphanumMask' : /[a-z0-9_]/i
50790 }();//<script type="text/javascript">
50793 * @class Roo.form.FCKeditor
50794 * @extends Roo.form.TextArea
50795 * Wrapper around the FCKEditor http://www.fckeditor.net
50797 * Creates a new FCKeditor
50798 * @param {Object} config Configuration options
50800 Roo.form.FCKeditor = function(config){
50801 Roo.form.FCKeditor.superclass.constructor.call(this, config);
50804 * @event editorinit
50805 * Fired when the editor is initialized - you can add extra handlers here..
50806 * @param {FCKeditor} this
50807 * @param {Object} the FCK object.
50814 Roo.form.FCKeditor.editors = { };
50815 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
50817 //defaultAutoCreate : {
50818 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
50822 * @cfg {Object} fck options - see fck manual for details.
50827 * @cfg {Object} fck toolbar set (Basic or Default)
50829 toolbarSet : 'Basic',
50831 * @cfg {Object} fck BasePath
50833 basePath : '/fckeditor/',
50841 onRender : function(ct, position)
50844 this.defaultAutoCreate = {
50846 style:"width:300px;height:60px;",
50847 autocomplete: "new-password"
50850 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
50853 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
50854 if(this.preventScrollbars){
50855 this.el.setStyle("overflow", "hidden");
50857 this.el.setHeight(this.growMin);
50860 //console.log('onrender' + this.getId() );
50861 Roo.form.FCKeditor.editors[this.getId()] = this;
50864 this.replaceTextarea() ;
50868 getEditor : function() {
50869 return this.fckEditor;
50872 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
50873 * @param {Mixed} value The value to set
50877 setValue : function(value)
50879 //console.log('setValue: ' + value);
50881 if(typeof(value) == 'undefined') { // not sure why this is happending...
50884 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
50886 //if(!this.el || !this.getEditor()) {
50887 // this.value = value;
50888 //this.setValue.defer(100,this,[value]);
50892 if(!this.getEditor()) {
50896 this.getEditor().SetData(value);
50903 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
50904 * @return {Mixed} value The field value
50906 getValue : function()
50909 if (this.frame && this.frame.dom.style.display == 'none') {
50910 return Roo.form.FCKeditor.superclass.getValue.call(this);
50913 if(!this.el || !this.getEditor()) {
50915 // this.getValue.defer(100,this);
50920 var value=this.getEditor().GetData();
50921 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
50922 return Roo.form.FCKeditor.superclass.getValue.call(this);
50928 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
50929 * @return {Mixed} value The field value
50931 getRawValue : function()
50933 if (this.frame && this.frame.dom.style.display == 'none') {
50934 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
50937 if(!this.el || !this.getEditor()) {
50938 //this.getRawValue.defer(100,this);
50945 var value=this.getEditor().GetData();
50946 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
50947 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
50951 setSize : function(w,h) {
50955 //if (this.frame && this.frame.dom.style.display == 'none') {
50956 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
50959 //if(!this.el || !this.getEditor()) {
50960 // this.setSize.defer(100,this, [w,h]);
50966 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
50968 this.frame.dom.setAttribute('width', w);
50969 this.frame.dom.setAttribute('height', h);
50970 this.frame.setSize(w,h);
50974 toggleSourceEdit : function(value) {
50978 this.el.dom.style.display = value ? '' : 'none';
50979 this.frame.dom.style.display = value ? 'none' : '';
50984 focus: function(tag)
50986 if (this.frame.dom.style.display == 'none') {
50987 return Roo.form.FCKeditor.superclass.focus.call(this);
50989 if(!this.el || !this.getEditor()) {
50990 this.focus.defer(100,this, [tag]);
50997 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
50998 this.getEditor().Focus();
51000 if (!this.getEditor().Selection.GetSelection()) {
51001 this.focus.defer(100,this, [tag]);
51006 var r = this.getEditor().EditorDocument.createRange();
51007 r.setStart(tgs[0],0);
51008 r.setEnd(tgs[0],0);
51009 this.getEditor().Selection.GetSelection().removeAllRanges();
51010 this.getEditor().Selection.GetSelection().addRange(r);
51011 this.getEditor().Focus();
51018 replaceTextarea : function()
51020 if ( document.getElementById( this.getId() + '___Frame' ) ) {
51023 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
51025 // We must check the elements firstly using the Id and then the name.
51026 var oTextarea = document.getElementById( this.getId() );
51028 var colElementsByName = document.getElementsByName( this.getId() ) ;
51030 oTextarea.style.display = 'none' ;
51032 if ( oTextarea.tabIndex ) {
51033 this.TabIndex = oTextarea.tabIndex ;
51036 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
51037 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
51038 this.frame = Roo.get(this.getId() + '___Frame')
51041 _getConfigHtml : function()
51045 for ( var o in this.fckconfig ) {
51046 sConfig += sConfig.length > 0 ? '&' : '';
51047 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
51050 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
51054 _getIFrameHtml : function()
51056 var sFile = 'fckeditor.html' ;
51057 /* no idea what this is about..
51060 if ( (/fcksource=true/i).test( window.top.location.search ) )
51061 sFile = 'fckeditor.original.html' ;
51066 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
51067 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
51070 var html = '<iframe id="' + this.getId() +
51071 '___Frame" src="' + sLink +
51072 '" width="' + this.width +
51073 '" height="' + this.height + '"' +
51074 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
51075 ' frameborder="0" scrolling="no"></iframe>' ;
51080 _insertHtmlBefore : function( html, element )
51082 if ( element.insertAdjacentHTML ) {
51084 element.insertAdjacentHTML( 'beforeBegin', html ) ;
51086 var oRange = document.createRange() ;
51087 oRange.setStartBefore( element ) ;
51088 var oFragment = oRange.createContextualFragment( html );
51089 element.parentNode.insertBefore( oFragment, element ) ;
51102 //Roo.reg('fckeditor', Roo.form.FCKeditor);
51104 function FCKeditor_OnComplete(editorInstance){
51105 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
51106 f.fckEditor = editorInstance;
51107 //console.log("loaded");
51108 f.fireEvent('editorinit', f, editorInstance);
51128 //<script type="text/javascript">
51130 * @class Roo.form.GridField
51131 * @extends Roo.form.Field
51132 * Embed a grid (or editable grid into a form)
51135 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
51137 * xgrid.store = Roo.data.Store
51138 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
51139 * xgrid.store.reader = Roo.data.JsonReader
51143 * Creates a new GridField
51144 * @param {Object} config Configuration options
51146 Roo.form.GridField = function(config){
51147 Roo.form.GridField.superclass.constructor.call(this, config);
51151 Roo.extend(Roo.form.GridField, Roo.form.Field, {
51153 * @cfg {Number} width - used to restrict width of grid..
51157 * @cfg {Number} height - used to restrict height of grid..
51161 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
51167 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
51168 * {tag: "input", type: "checkbox", autocomplete: "off"})
51170 // defaultAutoCreate : { tag: 'div' },
51171 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
51173 * @cfg {String} addTitle Text to include for adding a title.
51177 onResize : function(){
51178 Roo.form.Field.superclass.onResize.apply(this, arguments);
51181 initEvents : function(){
51182 // Roo.form.Checkbox.superclass.initEvents.call(this);
51183 // has no events...
51188 getResizeEl : function(){
51192 getPositionEl : function(){
51197 onRender : function(ct, position){
51199 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
51200 var style = this.style;
51203 Roo.form.GridField.superclass.onRender.call(this, ct, position);
51204 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
51205 this.viewEl = this.wrap.createChild({ tag: 'div' });
51207 this.viewEl.applyStyles(style);
51210 this.viewEl.setWidth(this.width);
51213 this.viewEl.setHeight(this.height);
51215 //if(this.inputValue !== undefined){
51216 //this.setValue(this.value);
51219 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
51222 this.grid.render();
51223 this.grid.getDataSource().on('remove', this.refreshValue, this);
51224 this.grid.getDataSource().on('update', this.refreshValue, this);
51225 this.grid.on('afteredit', this.refreshValue, this);
51231 * Sets the value of the item.
51232 * @param {String} either an object or a string..
51234 setValue : function(v){
51236 v = v || []; // empty set..
51237 // this does not seem smart - it really only affects memoryproxy grids..
51238 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
51239 var ds = this.grid.getDataSource();
51240 // assumes a json reader..
51242 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
51243 ds.loadData( data);
51245 // clear selection so it does not get stale.
51246 if (this.grid.sm) {
51247 this.grid.sm.clearSelections();
51250 Roo.form.GridField.superclass.setValue.call(this, v);
51251 this.refreshValue();
51252 // should load data in the grid really....
51256 refreshValue: function() {
51258 this.grid.getDataSource().each(function(r) {
51261 this.el.dom.value = Roo.encode(val);
51269 * Ext JS Library 1.1.1
51270 * Copyright(c) 2006-2007, Ext JS, LLC.
51272 * Originally Released Under LGPL - original licence link has changed is not relivant.
51275 * <script type="text/javascript">
51278 * @class Roo.form.DisplayField
51279 * @extends Roo.form.Field
51280 * A generic Field to display non-editable data.
51281 * @cfg {Boolean} closable (true|false) default false
51283 * Creates a new Display Field item.
51284 * @param {Object} config Configuration options
51286 Roo.form.DisplayField = function(config){
51287 Roo.form.DisplayField.superclass.constructor.call(this, config);
51292 * Fires after the click the close btn
51293 * @param {Roo.form.DisplayField} this
51299 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
51300 inputType: 'hidden',
51306 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
51308 focusClass : undefined,
51310 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
51312 fieldClass: 'x-form-field',
51315 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
51317 valueRenderer: undefined,
51321 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
51322 * {tag: "input", type: "checkbox", autocomplete: "off"})
51325 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
51329 onResize : function(){
51330 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
51334 initEvents : function(){
51335 // Roo.form.Checkbox.superclass.initEvents.call(this);
51336 // has no events...
51339 this.closeEl.on('click', this.onClose, this);
51345 getResizeEl : function(){
51349 getPositionEl : function(){
51354 onRender : function(ct, position){
51356 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
51357 //if(this.inputValue !== undefined){
51358 this.wrap = this.el.wrap();
51360 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
51363 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
51366 if (this.bodyStyle) {
51367 this.viewEl.applyStyles(this.bodyStyle);
51369 //this.viewEl.setStyle('padding', '2px');
51371 this.setValue(this.value);
51376 initValue : Roo.emptyFn,
51381 onClick : function(){
51386 * Sets the checked state of the checkbox.
51387 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
51389 setValue : function(v){
51391 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
51392 // this might be called before we have a dom element..
51393 if (!this.viewEl) {
51396 this.viewEl.dom.innerHTML = html;
51397 Roo.form.DisplayField.superclass.setValue.call(this, v);
51401 onClose : function(e)
51403 e.preventDefault();
51405 this.fireEvent('close', this);
51414 * @class Roo.form.DayPicker
51415 * @extends Roo.form.Field
51416 * A Day picker show [M] [T] [W] ....
51418 * Creates a new Day Picker
51419 * @param {Object} config Configuration options
51421 Roo.form.DayPicker= function(config){
51422 Roo.form.DayPicker.superclass.constructor.call(this, config);
51426 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
51428 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
51430 focusClass : undefined,
51432 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
51434 fieldClass: "x-form-field",
51437 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
51438 * {tag: "input", type: "checkbox", autocomplete: "off"})
51440 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
51443 actionMode : 'viewEl',
51447 inputType : 'hidden',
51450 inputElement: false, // real input element?
51451 basedOn: false, // ????
51453 isFormField: true, // not sure where this is needed!!!!
51455 onResize : function(){
51456 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
51457 if(!this.boxLabel){
51458 this.el.alignTo(this.wrap, 'c-c');
51462 initEvents : function(){
51463 Roo.form.Checkbox.superclass.initEvents.call(this);
51464 this.el.on("click", this.onClick, this);
51465 this.el.on("change", this.onClick, this);
51469 getResizeEl : function(){
51473 getPositionEl : function(){
51479 onRender : function(ct, position){
51480 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
51482 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
51484 var r1 = '<table><tr>';
51485 var r2 = '<tr class="x-form-daypick-icons">';
51486 for (var i=0; i < 7; i++) {
51487 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
51488 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
51491 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
51492 viewEl.select('img').on('click', this.onClick, this);
51493 this.viewEl = viewEl;
51496 // this will not work on Chrome!!!
51497 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
51498 this.el.on('propertychange', this.setFromHidden, this); //ie
51506 initValue : Roo.emptyFn,
51509 * Returns the checked state of the checkbox.
51510 * @return {Boolean} True if checked, else false
51512 getValue : function(){
51513 return this.el.dom.value;
51518 onClick : function(e){
51519 //this.setChecked(!this.checked);
51520 Roo.get(e.target).toggleClass('x-menu-item-checked');
51521 this.refreshValue();
51522 //if(this.el.dom.checked != this.checked){
51523 // this.setValue(this.el.dom.checked);
51528 refreshValue : function()
51531 this.viewEl.select('img',true).each(function(e,i,n) {
51532 val += e.is(".x-menu-item-checked") ? String(n) : '';
51534 this.setValue(val, true);
51538 * Sets the checked state of the checkbox.
51539 * On is always based on a string comparison between inputValue and the param.
51540 * @param {Boolean/String} value - the value to set
51541 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
51543 setValue : function(v,suppressEvent){
51544 if (!this.el.dom) {
51547 var old = this.el.dom.value ;
51548 this.el.dom.value = v;
51549 if (suppressEvent) {
51553 // update display..
51554 this.viewEl.select('img',true).each(function(e,i,n) {
51556 var on = e.is(".x-menu-item-checked");
51557 var newv = v.indexOf(String(n)) > -1;
51559 e.toggleClass('x-menu-item-checked');
51565 this.fireEvent('change', this, v, old);
51570 // handle setting of hidden value by some other method!!?!?
51571 setFromHidden: function()
51576 //console.log("SET FROM HIDDEN");
51577 //alert('setFrom hidden');
51578 this.setValue(this.el.dom.value);
51581 onDestroy : function()
51584 Roo.get(this.viewEl).remove();
51587 Roo.form.DayPicker.superclass.onDestroy.call(this);
51591 * RooJS Library 1.1.1
51592 * Copyright(c) 2008-2011 Alan Knowles
51599 * @class Roo.form.ComboCheck
51600 * @extends Roo.form.ComboBox
51601 * A combobox for multiple select items.
51603 * FIXME - could do with a reset button..
51606 * Create a new ComboCheck
51607 * @param {Object} config Configuration options
51609 Roo.form.ComboCheck = function(config){
51610 Roo.form.ComboCheck.superclass.constructor.call(this, config);
51611 // should verify some data...
51613 // hiddenName = required..
51614 // displayField = required
51615 // valudField == required
51616 var req= [ 'hiddenName', 'displayField', 'valueField' ];
51618 Roo.each(req, function(e) {
51619 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
51620 throw "Roo.form.ComboCheck : missing value for: " + e;
51627 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
51632 selectedClass: 'x-menu-item-checked',
51635 onRender : function(ct, position){
51641 var cls = 'x-combo-list';
51644 this.tpl = new Roo.Template({
51645 html : '<div class="'+cls+'-item x-menu-check-item">' +
51646 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
51647 '<span>{' + this.displayField + '}</span>' +
51654 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
51655 this.view.singleSelect = false;
51656 this.view.multiSelect = true;
51657 this.view.toggleSelect = true;
51658 this.pageTb.add(new Roo.Toolbar.Fill(), {
51661 handler: function()
51668 onViewOver : function(e, t){
51674 onViewClick : function(doFocus,index){
51678 select: function () {
51679 //Roo.log("SELECT CALLED");
51682 selectByValue : function(xv, scrollIntoView){
51683 var ar = this.getValueArray();
51686 Roo.each(ar, function(v) {
51687 if(v === undefined || v === null){
51690 var r = this.findRecord(this.valueField, v);
51692 sels.push(this.store.indexOf(r))
51696 this.view.select(sels);
51702 onSelect : function(record, index){
51703 // Roo.log("onselect Called");
51704 // this is only called by the clear button now..
51705 this.view.clearSelections();
51706 this.setValue('[]');
51707 if (this.value != this.valueBefore) {
51708 this.fireEvent('change', this, this.value, this.valueBefore);
51709 this.valueBefore = this.value;
51712 getValueArray : function()
51717 //Roo.log(this.value);
51718 if (typeof(this.value) == 'undefined') {
51721 var ar = Roo.decode(this.value);
51722 return ar instanceof Array ? ar : []; //?? valid?
51725 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
51730 expand : function ()
51733 Roo.form.ComboCheck.superclass.expand.call(this);
51734 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
51735 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
51740 collapse : function(){
51741 Roo.form.ComboCheck.superclass.collapse.call(this);
51742 var sl = this.view.getSelectedIndexes();
51743 var st = this.store;
51747 Roo.each(sl, function(i) {
51749 nv.push(r.get(this.valueField));
51751 this.setValue(Roo.encode(nv));
51752 if (this.value != this.valueBefore) {
51754 this.fireEvent('change', this, this.value, this.valueBefore);
51755 this.valueBefore = this.value;
51760 setValue : function(v){
51764 var vals = this.getValueArray();
51766 Roo.each(vals, function(k) {
51767 var r = this.findRecord(this.valueField, k);
51769 tv.push(r.data[this.displayField]);
51770 }else if(this.valueNotFoundText !== undefined){
51771 tv.push( this.valueNotFoundText );
51776 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
51777 this.hiddenField.value = v;
51783 * Ext JS Library 1.1.1
51784 * Copyright(c) 2006-2007, Ext JS, LLC.
51786 * Originally Released Under LGPL - original licence link has changed is not relivant.
51789 * <script type="text/javascript">
51793 * @class Roo.form.Signature
51794 * @extends Roo.form.Field
51798 * @param {Object} config Configuration options
51801 Roo.form.Signature = function(config){
51802 Roo.form.Signature.superclass.constructor.call(this, config);
51804 this.addEvents({// not in used??
51807 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
51808 * @param {Roo.form.Signature} combo This combo box
51813 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
51814 * @param {Roo.form.ComboBox} combo This combo box
51815 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
51821 Roo.extend(Roo.form.Signature, Roo.form.Field, {
51823 * @cfg {Object} labels Label to use when rendering a form.
51827 * confirm : "Confirm"
51832 confirm : "Confirm"
51835 * @cfg {Number} width The signature panel width (defaults to 300)
51839 * @cfg {Number} height The signature panel height (defaults to 100)
51843 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
51845 allowBlank : false,
51848 // {Object} signPanel The signature SVG panel element (defaults to {})
51850 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
51851 isMouseDown : false,
51852 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
51853 isConfirmed : false,
51854 // {String} signatureTmp SVG mapping string (defaults to empty string)
51858 defaultAutoCreate : { // modified by initCompnoent..
51864 onRender : function(ct, position){
51866 Roo.form.Signature.superclass.onRender.call(this, ct, position);
51868 this.wrap = this.el.wrap({
51869 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
51872 this.createToolbar(this);
51873 this.signPanel = this.wrap.createChild({
51875 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
51879 this.svgID = Roo.id();
51880 this.svgEl = this.signPanel.createChild({
51881 xmlns : 'http://www.w3.org/2000/svg',
51883 id : this.svgID + "-svg",
51885 height: this.height,
51886 viewBox: '0 0 '+this.width+' '+this.height,
51890 id: this.svgID + "-svg-r",
51892 height: this.height,
51897 id: this.svgID + "-svg-l",
51899 y1: (this.height*0.8), // start set the line in 80% of height
51900 x2: this.width, // end
51901 y2: (this.height*0.8), // end set the line in 80% of height
51903 'stroke-width': "1",
51904 'stroke-dasharray': "3",
51905 'shape-rendering': "crispEdges",
51906 'pointer-events': "none"
51910 id: this.svgID + "-svg-p",
51912 'stroke-width': "3",
51914 'pointer-events': 'none'
51919 this.svgBox = this.svgEl.dom.getScreenCTM();
51921 createSVG : function(){
51922 var svg = this.signPanel;
51923 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
51926 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
51927 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
51928 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
51929 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
51930 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
51931 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
51932 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
51935 isTouchEvent : function(e){
51936 return e.type.match(/^touch/);
51938 getCoords : function (e) {
51939 var pt = this.svgEl.dom.createSVGPoint();
51942 if (this.isTouchEvent(e)) {
51943 pt.x = e.targetTouches[0].clientX;
51944 pt.y = e.targetTouches[0].clientY;
51946 var a = this.svgEl.dom.getScreenCTM();
51947 var b = a.inverse();
51948 var mx = pt.matrixTransform(b);
51949 return mx.x + ',' + mx.y;
51951 //mouse event headler
51952 down : function (e) {
51953 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
51954 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
51956 this.isMouseDown = true;
51958 e.preventDefault();
51960 move : function (e) {
51961 if (this.isMouseDown) {
51962 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
51963 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
51966 e.preventDefault();
51968 up : function (e) {
51969 this.isMouseDown = false;
51970 var sp = this.signatureTmp.split(' ');
51973 if(!sp[sp.length-2].match(/^L/)){
51977 this.signatureTmp = sp.join(" ");
51980 if(this.getValue() != this.signatureTmp){
51981 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
51982 this.isConfirmed = false;
51984 e.preventDefault();
51988 * Protected method that will not generally be called directly. It
51989 * is called when the editor creates its toolbar. Override this method if you need to
51990 * add custom toolbar buttons.
51991 * @param {HtmlEditor} editor
51993 createToolbar : function(editor){
51994 function btn(id, toggle, handler){
51995 var xid = fid + '-'+ id ;
51999 cls : 'x-btn-icon x-edit-'+id,
52000 enableToggle:toggle !== false,
52001 scope: editor, // was editor...
52002 handler:handler||editor.relayBtnCmd,
52003 clickEvent:'mousedown',
52004 tooltip: etb.buttonTips[id] || undefined, ///tips ???
52010 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
52014 cls : ' x-signature-btn x-signature-'+id,
52015 scope: editor, // was editor...
52016 handler: this.reset,
52017 clickEvent:'mousedown',
52018 text: this.labels.clear
52025 cls : ' x-signature-btn x-signature-'+id,
52026 scope: editor, // was editor...
52027 handler: this.confirmHandler,
52028 clickEvent:'mousedown',
52029 text: this.labels.confirm
52036 * when user is clicked confirm then show this image.....
52038 * @return {String} Image Data URI
52040 getImageDataURI : function(){
52041 var svg = this.svgEl.dom.parentNode.innerHTML;
52042 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
52047 * @return {Boolean} this.isConfirmed
52049 getConfirmed : function(){
52050 return this.isConfirmed;
52054 * @return {Number} this.width
52056 getWidth : function(){
52061 * @return {Number} this.height
52063 getHeight : function(){
52064 return this.height;
52067 getSignature : function(){
52068 return this.signatureTmp;
52071 reset : function(){
52072 this.signatureTmp = '';
52073 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
52074 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
52075 this.isConfirmed = false;
52076 Roo.form.Signature.superclass.reset.call(this);
52078 setSignature : function(s){
52079 this.signatureTmp = s;
52080 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
52081 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
52083 this.isConfirmed = false;
52084 Roo.form.Signature.superclass.reset.call(this);
52087 // Roo.log(this.signPanel.dom.contentWindow.up())
52090 setConfirmed : function(){
52094 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
52097 confirmHandler : function(){
52098 if(!this.getSignature()){
52102 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
52103 this.setValue(this.getSignature());
52104 this.isConfirmed = true;
52106 this.fireEvent('confirm', this);
52109 // Subclasses should provide the validation implementation by overriding this
52110 validateValue : function(value){
52111 if(this.allowBlank){
52115 if(this.isConfirmed){
52122 * Ext JS Library 1.1.1
52123 * Copyright(c) 2006-2007, Ext JS, LLC.
52125 * Originally Released Under LGPL - original licence link has changed is not relivant.
52128 * <script type="text/javascript">
52133 * @class Roo.form.ComboBox
52134 * @extends Roo.form.TriggerField
52135 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
52137 * Create a new ComboBox.
52138 * @param {Object} config Configuration options
52140 Roo.form.Select = function(config){
52141 Roo.form.Select.superclass.constructor.call(this, config);
52145 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
52147 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
52150 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
52151 * rendering into an Roo.Editor, defaults to false)
52154 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
52155 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
52158 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
52161 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
52162 * the dropdown list (defaults to undefined, with no header element)
52166 * @cfg {String/Roo.Template} tpl The template to use to render the output
52170 defaultAutoCreate : {tag: "select" },
52172 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
52174 listWidth: undefined,
52176 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
52177 * mode = 'remote' or 'text' if mode = 'local')
52179 displayField: undefined,
52181 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
52182 * mode = 'remote' or 'value' if mode = 'local').
52183 * Note: use of a valueField requires the user make a selection
52184 * in order for a value to be mapped.
52186 valueField: undefined,
52190 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
52191 * field's data value (defaults to the underlying DOM element's name)
52193 hiddenName: undefined,
52195 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
52199 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
52201 selectedClass: 'x-combo-selected',
52203 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
52204 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
52205 * which displays a downward arrow icon).
52207 triggerClass : 'x-form-arrow-trigger',
52209 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
52213 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
52214 * anchor positions (defaults to 'tl-bl')
52216 listAlign: 'tl-bl?',
52218 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
52222 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
52223 * query specified by the allQuery config option (defaults to 'query')
52225 triggerAction: 'query',
52227 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
52228 * (defaults to 4, does not apply if editable = false)
52232 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
52233 * delay (typeAheadDelay) if it matches a known value (defaults to false)
52237 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
52238 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
52242 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
52243 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
52247 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
52248 * when editable = true (defaults to false)
52250 selectOnFocus:false,
52252 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
52254 queryParam: 'query',
52256 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
52257 * when mode = 'remote' (defaults to 'Loading...')
52259 loadingText: 'Loading...',
52261 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
52265 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
52269 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
52270 * traditional select (defaults to true)
52274 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
52278 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
52282 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
52283 * listWidth has a higher value)
52287 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
52288 * allow the user to set arbitrary text into the field (defaults to false)
52290 forceSelection:false,
52292 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
52293 * if typeAhead = true (defaults to 250)
52295 typeAheadDelay : 250,
52297 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
52298 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
52300 valueNotFoundText : undefined,
52303 * @cfg {String} defaultValue The value displayed after loading the store.
52308 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
52310 blockFocus : false,
52313 * @cfg {Boolean} disableClear Disable showing of clear button.
52315 disableClear : false,
52317 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
52319 alwaysQuery : false,
52325 // element that contains real text value.. (when hidden is used..)
52328 onRender : function(ct, position){
52329 Roo.form.Field.prototype.onRender.call(this, ct, position);
52332 this.store.on('beforeload', this.onBeforeLoad, this);
52333 this.store.on('load', this.onLoad, this);
52334 this.store.on('loadexception', this.onLoadException, this);
52335 this.store.load({});
52343 initEvents : function(){
52344 //Roo.form.ComboBox.superclass.initEvents.call(this);
52348 onDestroy : function(){
52351 this.store.un('beforeload', this.onBeforeLoad, this);
52352 this.store.un('load', this.onLoad, this);
52353 this.store.un('loadexception', this.onLoadException, this);
52355 //Roo.form.ComboBox.superclass.onDestroy.call(this);
52359 fireKey : function(e){
52360 if(e.isNavKeyPress() && !this.list.isVisible()){
52361 this.fireEvent("specialkey", this, e);
52366 onResize: function(w, h){
52374 * Allow or prevent the user from directly editing the field text. If false is passed,
52375 * the user will only be able to select from the items defined in the dropdown list. This method
52376 * is the runtime equivalent of setting the 'editable' config option at config time.
52377 * @param {Boolean} value True to allow the user to directly edit the field text
52379 setEditable : function(value){
52384 onBeforeLoad : function(){
52386 Roo.log("Select before load");
52389 this.innerList.update(this.loadingText ?
52390 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
52391 //this.restrictHeight();
52392 this.selectedIndex = -1;
52396 onLoad : function(){
52399 var dom = this.el.dom;
52400 dom.innerHTML = '';
52401 var od = dom.ownerDocument;
52403 if (this.emptyText) {
52404 var op = od.createElement('option');
52405 op.setAttribute('value', '');
52406 op.innerHTML = String.format('{0}', this.emptyText);
52407 dom.appendChild(op);
52409 if(this.store.getCount() > 0){
52411 var vf = this.valueField;
52412 var df = this.displayField;
52413 this.store.data.each(function(r) {
52414 // which colmsn to use... testing - cdoe / title..
52415 var op = od.createElement('option');
52416 op.setAttribute('value', r.data[vf]);
52417 op.innerHTML = String.format('{0}', r.data[df]);
52418 dom.appendChild(op);
52420 if (typeof(this.defaultValue != 'undefined')) {
52421 this.setValue(this.defaultValue);
52426 //this.onEmptyResults();
52431 onLoadException : function()
52433 dom.innerHTML = '';
52435 Roo.log("Select on load exception");
52439 Roo.log(this.store.reader.jsonData);
52440 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
52441 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
52447 onTypeAhead : function(){
52452 onSelect : function(record, index){
52453 Roo.log('on select?');
52455 if(this.fireEvent('beforeselect', this, record, index) !== false){
52456 this.setFromData(index > -1 ? record.data : false);
52458 this.fireEvent('select', this, record, index);
52463 * Returns the currently selected field value or empty string if no value is set.
52464 * @return {String} value The selected value
52466 getValue : function(){
52467 var dom = this.el.dom;
52468 this.value = dom.options[dom.selectedIndex].value;
52474 * Clears any text/value currently set in the field
52476 clearValue : function(){
52478 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
52483 * Sets the specified value into the field. If the value finds a match, the corresponding record text
52484 * will be displayed in the field. If the value does not match the data value of an existing item,
52485 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
52486 * Otherwise the field will be blank (although the value will still be set).
52487 * @param {String} value The value to match
52489 setValue : function(v){
52490 var d = this.el.dom;
52491 for (var i =0; i < d.options.length;i++) {
52492 if (v == d.options[i].value) {
52493 d.selectedIndex = i;
52501 * @property {Object} the last set data for the element
52506 * Sets the value of the field based on a object which is related to the record format for the store.
52507 * @param {Object} value the value to set as. or false on reset?
52509 setFromData : function(o){
52510 Roo.log('setfrom data?');
52516 reset : function(){
52520 findRecord : function(prop, value){
52525 if(this.store.getCount() > 0){
52526 this.store.each(function(r){
52527 if(r.data[prop] == value){
52537 getName: function()
52539 // returns hidden if it's set..
52540 if (!this.rendered) {return ''};
52541 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
52549 onEmptyResults : function(){
52550 Roo.log('empty results');
52555 * Returns true if the dropdown list is expanded, else false.
52557 isExpanded : function(){
52562 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
52563 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
52564 * @param {String} value The data value of the item to select
52565 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
52566 * selected item if it is not currently in view (defaults to true)
52567 * @return {Boolean} True if the value matched an item in the list, else false
52569 selectByValue : function(v, scrollIntoView){
52570 Roo.log('select By Value');
52573 if(v !== undefined && v !== null){
52574 var r = this.findRecord(this.valueField || this.displayField, v);
52576 this.select(this.store.indexOf(r), scrollIntoView);
52584 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
52585 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
52586 * @param {Number} index The zero-based index of the list item to select
52587 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
52588 * selected item if it is not currently in view (defaults to true)
52590 select : function(index, scrollIntoView){
52591 Roo.log('select ');
52594 this.selectedIndex = index;
52595 this.view.select(index);
52596 if(scrollIntoView !== false){
52597 var el = this.view.getNode(index);
52599 this.innerList.scrollChildIntoView(el, false);
52607 validateBlur : function(){
52614 initQuery : function(){
52615 this.doQuery(this.getRawValue());
52619 doForce : function(){
52620 if(this.el.dom.value.length > 0){
52621 this.el.dom.value =
52622 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
52628 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
52629 * query allowing the query action to be canceled if needed.
52630 * @param {String} query The SQL query to execute
52631 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
52632 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
52633 * saved in the current store (defaults to false)
52635 doQuery : function(q, forceAll){
52637 Roo.log('doQuery?');
52638 if(q === undefined || q === null){
52643 forceAll: forceAll,
52647 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
52651 forceAll = qe.forceAll;
52652 if(forceAll === true || (q.length >= this.minChars)){
52653 if(this.lastQuery != q || this.alwaysQuery){
52654 this.lastQuery = q;
52655 if(this.mode == 'local'){
52656 this.selectedIndex = -1;
52658 this.store.clearFilter();
52660 this.store.filter(this.displayField, q);
52664 this.store.baseParams[this.queryParam] = q;
52666 params: this.getParams(q)
52671 this.selectedIndex = -1;
52678 getParams : function(q){
52680 //p[this.queryParam] = q;
52683 p.limit = this.pageSize;
52689 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
52691 collapse : function(){
52696 collapseIf : function(e){
52701 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
52703 expand : function(){
52711 * @cfg {Boolean} grow
52715 * @cfg {Number} growMin
52719 * @cfg {Number} growMax
52727 setWidth : function()
52731 getResizeEl : function(){
52734 });//<script type="text/javasscript">
52738 * @class Roo.DDView
52739 * A DnD enabled version of Roo.View.
52740 * @param {Element/String} container The Element in which to create the View.
52741 * @param {String} tpl The template string used to create the markup for each element of the View
52742 * @param {Object} config The configuration properties. These include all the config options of
52743 * {@link Roo.View} plus some specific to this class.<br>
52745 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
52746 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
52748 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
52749 .x-view-drag-insert-above {
52750 border-top:1px dotted #3366cc;
52752 .x-view-drag-insert-below {
52753 border-bottom:1px dotted #3366cc;
52759 Roo.DDView = function(container, tpl, config) {
52760 Roo.DDView.superclass.constructor.apply(this, arguments);
52761 this.getEl().setStyle("outline", "0px none");
52762 this.getEl().unselectable();
52763 if (this.dragGroup) {
52764 this.setDraggable(this.dragGroup.split(","));
52766 if (this.dropGroup) {
52767 this.setDroppable(this.dropGroup.split(","));
52769 if (this.deletable) {
52770 this.setDeletable();
52772 this.isDirtyFlag = false;
52778 Roo.extend(Roo.DDView, Roo.View, {
52779 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
52780 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
52781 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
52782 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
52786 reset: Roo.emptyFn,
52788 clearInvalid: Roo.form.Field.prototype.clearInvalid,
52790 validate: function() {
52794 destroy: function() {
52795 this.purgeListeners();
52796 this.getEl.removeAllListeners();
52797 this.getEl().remove();
52798 if (this.dragZone) {
52799 if (this.dragZone.destroy) {
52800 this.dragZone.destroy();
52803 if (this.dropZone) {
52804 if (this.dropZone.destroy) {
52805 this.dropZone.destroy();
52810 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
52811 getName: function() {
52815 /** Loads the View from a JSON string representing the Records to put into the Store. */
52816 setValue: function(v) {
52818 throw "DDView.setValue(). DDView must be constructed with a valid Store";
52821 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
52822 this.store.proxy = new Roo.data.MemoryProxy(data);
52826 /** @return {String} a parenthesised list of the ids of the Records in the View. */
52827 getValue: function() {
52829 this.store.each(function(rec) {
52830 result += rec.id + ',';
52832 return result.substr(0, result.length - 1) + ')';
52835 getIds: function() {
52836 var i = 0, result = new Array(this.store.getCount());
52837 this.store.each(function(rec) {
52838 result[i++] = rec.id;
52843 isDirty: function() {
52844 return this.isDirtyFlag;
52848 * Part of the Roo.dd.DropZone interface. If no target node is found, the
52849 * whole Element becomes the target, and this causes the drop gesture to append.
52851 getTargetFromEvent : function(e) {
52852 var target = e.getTarget();
52853 while ((target !== null) && (target.parentNode != this.el.dom)) {
52854 target = target.parentNode;
52857 target = this.el.dom.lastChild || this.el.dom;
52863 * Create the drag data which consists of an object which has the property "ddel" as
52864 * the drag proxy element.
52866 getDragData : function(e) {
52867 var target = this.findItemFromChild(e.getTarget());
52869 this.handleSelection(e);
52870 var selNodes = this.getSelectedNodes();
52873 copy: this.copy || (this.allowCopy && e.ctrlKey),
52877 var selectedIndices = this.getSelectedIndexes();
52878 for (var i = 0; i < selectedIndices.length; i++) {
52879 dragData.records.push(this.store.getAt(selectedIndices[i]));
52881 if (selNodes.length == 1) {
52882 dragData.ddel = target.cloneNode(true); // the div element
52884 var div = document.createElement('div'); // create the multi element drag "ghost"
52885 div.className = 'multi-proxy';
52886 for (var i = 0, len = selNodes.length; i < len; i++) {
52887 div.appendChild(selNodes[i].cloneNode(true));
52889 dragData.ddel = div;
52891 //console.log(dragData)
52892 //console.log(dragData.ddel.innerHTML)
52895 //console.log('nodragData')
52899 /** Specify to which ddGroup items in this DDView may be dragged. */
52900 setDraggable: function(ddGroup) {
52901 if (ddGroup instanceof Array) {
52902 Roo.each(ddGroup, this.setDraggable, this);
52905 if (this.dragZone) {
52906 this.dragZone.addToGroup(ddGroup);
52908 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
52909 containerScroll: true,
52913 // Draggability implies selection. DragZone's mousedown selects the element.
52914 if (!this.multiSelect) { this.singleSelect = true; }
52916 // Wire the DragZone's handlers up to methods in *this*
52917 this.dragZone.getDragData = this.getDragData.createDelegate(this);
52921 /** Specify from which ddGroup this DDView accepts drops. */
52922 setDroppable: function(ddGroup) {
52923 if (ddGroup instanceof Array) {
52924 Roo.each(ddGroup, this.setDroppable, this);
52927 if (this.dropZone) {
52928 this.dropZone.addToGroup(ddGroup);
52930 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
52931 containerScroll: true,
52935 // Wire the DropZone's handlers up to methods in *this*
52936 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
52937 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
52938 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
52939 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
52940 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
52944 /** Decide whether to drop above or below a View node. */
52945 getDropPoint : function(e, n, dd){
52946 if (n == this.el.dom) { return "above"; }
52947 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
52948 var c = t + (b - t) / 2;
52949 var y = Roo.lib.Event.getPageY(e);
52957 onNodeEnter : function(n, dd, e, data){
52961 onNodeOver : function(n, dd, e, data){
52962 var pt = this.getDropPoint(e, n, dd);
52963 // set the insert point style on the target node
52964 var dragElClass = this.dropNotAllowed;
52967 if (pt == "above"){
52968 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
52969 targetElClass = "x-view-drag-insert-above";
52971 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
52972 targetElClass = "x-view-drag-insert-below";
52974 if (this.lastInsertClass != targetElClass){
52975 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
52976 this.lastInsertClass = targetElClass;
52979 return dragElClass;
52982 onNodeOut : function(n, dd, e, data){
52983 this.removeDropIndicators(n);
52986 onNodeDrop : function(n, dd, e, data){
52987 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
52990 var pt = this.getDropPoint(e, n, dd);
52991 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
52992 if (pt == "below") { insertAt++; }
52993 for (var i = 0; i < data.records.length; i++) {
52994 var r = data.records[i];
52995 var dup = this.store.getById(r.id);
52996 if (dup && (dd != this.dragZone)) {
52997 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
53000 this.store.insert(insertAt++, r.copy());
53002 data.source.isDirtyFlag = true;
53004 this.store.insert(insertAt++, r);
53006 this.isDirtyFlag = true;
53009 this.dragZone.cachedTarget = null;
53013 removeDropIndicators : function(n){
53015 Roo.fly(n).removeClass([
53016 "x-view-drag-insert-above",
53017 "x-view-drag-insert-below"]);
53018 this.lastInsertClass = "_noclass";
53023 * Utility method. Add a delete option to the DDView's context menu.
53024 * @param {String} imageUrl The URL of the "delete" icon image.
53026 setDeletable: function(imageUrl) {
53027 if (!this.singleSelect && !this.multiSelect) {
53028 this.singleSelect = true;
53030 var c = this.getContextMenu();
53031 this.contextMenu.on("itemclick", function(item) {
53034 this.remove(this.getSelectedIndexes());
53038 this.contextMenu.add({
53045 /** Return the context menu for this DDView. */
53046 getContextMenu: function() {
53047 if (!this.contextMenu) {
53048 // Create the View's context menu
53049 this.contextMenu = new Roo.menu.Menu({
53050 id: this.id + "-contextmenu"
53052 this.el.on("contextmenu", this.showContextMenu, this);
53054 return this.contextMenu;
53057 disableContextMenu: function() {
53058 if (this.contextMenu) {
53059 this.el.un("contextmenu", this.showContextMenu, this);
53063 showContextMenu: function(e, item) {
53064 item = this.findItemFromChild(e.getTarget());
53067 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
53068 this.contextMenu.showAt(e.getXY());
53073 * Remove {@link Roo.data.Record}s at the specified indices.
53074 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
53076 remove: function(selectedIndices) {
53077 selectedIndices = [].concat(selectedIndices);
53078 for (var i = 0; i < selectedIndices.length; i++) {
53079 var rec = this.store.getAt(selectedIndices[i]);
53080 this.store.remove(rec);
53085 * Double click fires the event, but also, if this is draggable, and there is only one other
53086 * related DropZone, it transfers the selected node.
53088 onDblClick : function(e){
53089 var item = this.findItemFromChild(e.getTarget());
53091 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
53094 if (this.dragGroup) {
53095 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
53096 while (targets.indexOf(this.dropZone) > -1) {
53097 targets.remove(this.dropZone);
53099 if (targets.length == 1) {
53100 this.dragZone.cachedTarget = null;
53101 var el = Roo.get(targets[0].getEl());
53102 var box = el.getBox(true);
53103 targets[0].onNodeDrop(el.dom, {
53105 xy: [box.x, box.y + box.height - 1]
53106 }, null, this.getDragData(e));
53112 handleSelection: function(e) {
53113 this.dragZone.cachedTarget = null;
53114 var item = this.findItemFromChild(e.getTarget());
53116 this.clearSelections(true);
53119 if (item && (this.multiSelect || this.singleSelect)){
53120 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
53121 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
53122 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
53123 this.unselect(item);
53125 this.select(item, this.multiSelect && e.ctrlKey);
53126 this.lastSelection = item;
53131 onItemClick : function(item, index, e){
53132 if(this.fireEvent("beforeclick", this, index, item, e) === false){
53138 unselect : function(nodeInfo, suppressEvent){
53139 var node = this.getNode(nodeInfo);
53140 if(node && this.isSelected(node)){
53141 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
53142 Roo.fly(node).removeClass(this.selectedClass);
53143 this.selections.remove(node);
53144 if(!suppressEvent){
53145 this.fireEvent("selectionchange", this, this.selections);
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">
53163 * @class Roo.LayoutManager
53164 * @extends Roo.util.Observable
53165 * Base class for layout managers.
53167 Roo.LayoutManager = function(container, config){
53168 Roo.LayoutManager.superclass.constructor.call(this);
53169 this.el = Roo.get(container);
53170 // ie scrollbar fix
53171 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
53172 document.body.scroll = "no";
53173 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
53174 this.el.position('relative');
53176 this.id = this.el.id;
53177 this.el.addClass("x-layout-container");
53178 /** false to disable window resize monitoring @type Boolean */
53179 this.monitorWindowResize = true;
53184 * Fires when a layout is performed.
53185 * @param {Roo.LayoutManager} this
53189 * @event regionresized
53190 * Fires when the user resizes a region.
53191 * @param {Roo.LayoutRegion} region The resized region
53192 * @param {Number} newSize The new size (width for east/west, height for north/south)
53194 "regionresized" : true,
53196 * @event regioncollapsed
53197 * Fires when a region is collapsed.
53198 * @param {Roo.LayoutRegion} region The collapsed region
53200 "regioncollapsed" : true,
53202 * @event regionexpanded
53203 * Fires when a region is expanded.
53204 * @param {Roo.LayoutRegion} region The expanded region
53206 "regionexpanded" : true
53208 this.updating = false;
53209 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
53212 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
53214 * Returns true if this layout is currently being updated
53215 * @return {Boolean}
53217 isUpdating : function(){
53218 return this.updating;
53222 * Suspend the LayoutManager from doing auto-layouts while
53223 * making multiple add or remove calls
53225 beginUpdate : function(){
53226 this.updating = true;
53230 * Restore auto-layouts and optionally disable the manager from performing a layout
53231 * @param {Boolean} noLayout true to disable a layout update
53233 endUpdate : function(noLayout){
53234 this.updating = false;
53240 layout: function(){
53244 onRegionResized : function(region, newSize){
53245 this.fireEvent("regionresized", region, newSize);
53249 onRegionCollapsed : function(region){
53250 this.fireEvent("regioncollapsed", region);
53253 onRegionExpanded : function(region){
53254 this.fireEvent("regionexpanded", region);
53258 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
53259 * performs box-model adjustments.
53260 * @return {Object} The size as an object {width: (the width), height: (the height)}
53262 getViewSize : function(){
53264 if(this.el.dom != document.body){
53265 size = this.el.getSize();
53267 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
53269 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
53270 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
53275 * Returns the Element this layout is bound to.
53276 * @return {Roo.Element}
53278 getEl : function(){
53283 * Returns the specified region.
53284 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
53285 * @return {Roo.LayoutRegion}
53287 getRegion : function(target){
53288 return this.regions[target.toLowerCase()];
53291 onWindowResize : function(){
53292 if(this.monitorWindowResize){
53298 * Ext JS Library 1.1.1
53299 * Copyright(c) 2006-2007, Ext JS, LLC.
53301 * Originally Released Under LGPL - original licence link has changed is not relivant.
53304 * <script type="text/javascript">
53307 * @class Roo.BorderLayout
53308 * @extends Roo.LayoutManager
53309 * @children Roo.ContentPanel
53310 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
53311 * please see: <br><br>
53312 * <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>
53313 * <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>
53316 var layout = new Roo.BorderLayout(document.body, {
53350 preferredTabWidth: 150
53355 var CP = Roo.ContentPanel;
53357 layout.beginUpdate();
53358 layout.add("north", new CP("north", "North"));
53359 layout.add("south", new CP("south", {title: "South", closable: true}));
53360 layout.add("west", new CP("west", {title: "West"}));
53361 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
53362 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
53363 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
53364 layout.getRegion("center").showPanel("center1");
53365 layout.endUpdate();
53368 <b>The container the layout is rendered into can be either the body element or any other element.
53369 If it is not the body element, the container needs to either be an absolute positioned element,
53370 or you will need to add "position:relative" to the css of the container. You will also need to specify
53371 the container size if it is not the body element.</b>
53374 * Create a new BorderLayout
53375 * @param {String/HTMLElement/Element} container The container this layout is bound to
53376 * @param {Object} config Configuration options
53378 Roo.BorderLayout = function(container, config){
53379 config = config || {};
53380 Roo.BorderLayout.superclass.constructor.call(this, container, config);
53381 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
53382 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
53383 var target = this.factory.validRegions[i];
53384 if(config[target]){
53385 this.addRegion(target, config[target]);
53390 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
53393 * @cfg {Roo.LayoutRegion} east
53396 * @cfg {Roo.LayoutRegion} west
53399 * @cfg {Roo.LayoutRegion} north
53402 * @cfg {Roo.LayoutRegion} south
53405 * @cfg {Roo.LayoutRegion} center
53408 * Creates and adds a new region if it doesn't already exist.
53409 * @param {String} target The target region key (north, south, east, west or center).
53410 * @param {Object} config The regions config object
53411 * @return {BorderLayoutRegion} The new region
53413 addRegion : function(target, config){
53414 if(!this.regions[target]){
53415 var r = this.factory.create(target, this, config);
53416 this.bindRegion(target, r);
53418 return this.regions[target];
53422 bindRegion : function(name, r){
53423 this.regions[name] = r;
53424 r.on("visibilitychange", this.layout, this);
53425 r.on("paneladded", this.layout, this);
53426 r.on("panelremoved", this.layout, this);
53427 r.on("invalidated", this.layout, this);
53428 r.on("resized", this.onRegionResized, this);
53429 r.on("collapsed", this.onRegionCollapsed, this);
53430 r.on("expanded", this.onRegionExpanded, this);
53434 * Performs a layout update.
53436 layout : function(){
53437 if(this.updating) {
53440 var size = this.getViewSize();
53441 var w = size.width;
53442 var h = size.height;
53447 //var x = 0, y = 0;
53449 var rs = this.regions;
53450 var north = rs["north"];
53451 var south = rs["south"];
53452 var west = rs["west"];
53453 var east = rs["east"];
53454 var center = rs["center"];
53455 //if(this.hideOnLayout){ // not supported anymore
53456 //c.el.setStyle("display", "none");
53458 if(north && north.isVisible()){
53459 var b = north.getBox();
53460 var m = north.getMargins();
53461 b.width = w - (m.left+m.right);
53464 centerY = b.height + b.y + m.bottom;
53465 centerH -= centerY;
53466 north.updateBox(this.safeBox(b));
53468 if(south && south.isVisible()){
53469 var b = south.getBox();
53470 var m = south.getMargins();
53471 b.width = w - (m.left+m.right);
53473 var totalHeight = (b.height + m.top + m.bottom);
53474 b.y = h - totalHeight + m.top;
53475 centerH -= totalHeight;
53476 south.updateBox(this.safeBox(b));
53478 if(west && west.isVisible()){
53479 var b = west.getBox();
53480 var m = west.getMargins();
53481 b.height = centerH - (m.top+m.bottom);
53483 b.y = centerY + m.top;
53484 var totalWidth = (b.width + m.left + m.right);
53485 centerX += totalWidth;
53486 centerW -= totalWidth;
53487 west.updateBox(this.safeBox(b));
53489 if(east && east.isVisible()){
53490 var b = east.getBox();
53491 var m = east.getMargins();
53492 b.height = centerH - (m.top+m.bottom);
53493 var totalWidth = (b.width + m.left + m.right);
53494 b.x = w - totalWidth + m.left;
53495 b.y = centerY + m.top;
53496 centerW -= totalWidth;
53497 east.updateBox(this.safeBox(b));
53500 var m = center.getMargins();
53502 x: centerX + m.left,
53503 y: centerY + m.top,
53504 width: centerW - (m.left+m.right),
53505 height: centerH - (m.top+m.bottom)
53507 //if(this.hideOnLayout){
53508 //center.el.setStyle("display", "block");
53510 center.updateBox(this.safeBox(centerBox));
53513 this.fireEvent("layout", this);
53517 safeBox : function(box){
53518 box.width = Math.max(0, box.width);
53519 box.height = Math.max(0, box.height);
53524 * Adds a ContentPanel (or subclass) to this layout.
53525 * @param {String} target The target region key (north, south, east, west or center).
53526 * @param {Roo.ContentPanel} panel The panel to add
53527 * @return {Roo.ContentPanel} The added panel
53529 add : function(target, panel){
53531 target = target.toLowerCase();
53532 return this.regions[target].add(panel);
53536 * Remove a ContentPanel (or subclass) to this layout.
53537 * @param {String} target The target region key (north, south, east, west or center).
53538 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
53539 * @return {Roo.ContentPanel} The removed panel
53541 remove : function(target, panel){
53542 target = target.toLowerCase();
53543 return this.regions[target].remove(panel);
53547 * Searches all regions for a panel with the specified id
53548 * @param {String} panelId
53549 * @return {Roo.ContentPanel} The panel or null if it wasn't found
53551 findPanel : function(panelId){
53552 var rs = this.regions;
53553 for(var target in rs){
53554 if(typeof rs[target] != "function"){
53555 var p = rs[target].getPanel(panelId);
53565 * Searches all regions for a panel with the specified id and activates (shows) it.
53566 * @param {String/ContentPanel} panelId The panels id or the panel itself
53567 * @return {Roo.ContentPanel} The shown panel or null
53569 showPanel : function(panelId) {
53570 var rs = this.regions;
53571 for(var target in rs){
53572 var r = rs[target];
53573 if(typeof r != "function"){
53574 if(r.hasPanel(panelId)){
53575 return r.showPanel(panelId);
53583 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
53584 * @param {Roo.state.Provider} provider (optional) An alternate state provider
53586 restoreState : function(provider){
53588 provider = Roo.state.Manager;
53590 var sm = new Roo.LayoutStateManager();
53591 sm.init(this, provider);
53595 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
53596 * object should contain properties for each region to add ContentPanels to, and each property's value should be
53597 * a valid ContentPanel config object. Example:
53599 // Create the main layout
53600 var layout = new Roo.BorderLayout('main-ct', {
53611 // Create and add multiple ContentPanels at once via configs
53614 id: 'source-files',
53616 title:'Ext Source Files',
53629 * @param {Object} regions An object containing ContentPanel configs by region name
53631 batchAdd : function(regions){
53632 this.beginUpdate();
53633 for(var rname in regions){
53634 var lr = this.regions[rname];
53636 this.addTypedPanels(lr, regions[rname]);
53643 addTypedPanels : function(lr, ps){
53644 if(typeof ps == 'string'){
53645 lr.add(new Roo.ContentPanel(ps));
53647 else if(ps instanceof Array){
53648 for(var i =0, len = ps.length; i < len; i++){
53649 this.addTypedPanels(lr, ps[i]);
53652 else if(!ps.events){ // raw config?
53654 delete ps.el; // prevent conflict
53655 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
53657 else { // panel object assumed!
53662 * Adds a xtype elements to the layout.
53666 xtype : 'ContentPanel',
53673 xtype : 'NestedLayoutPanel',
53679 items : [ ... list of content panels or nested layout panels.. ]
53683 * @param {Object} cfg Xtype definition of item to add.
53685 addxtype : function(cfg)
53687 // basically accepts a pannel...
53688 // can accept a layout region..!?!?
53689 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
53691 if (!cfg.xtype.match(/Panel$/)) {
53696 if (typeof(cfg.region) == 'undefined') {
53697 Roo.log("Failed to add Panel, region was not set");
53701 var region = cfg.region;
53707 xitems = cfg.items;
53714 case 'ContentPanel': // ContentPanel (el, cfg)
53715 case 'ScrollPanel': // ContentPanel (el, cfg)
53717 if(cfg.autoCreate) {
53718 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
53720 var el = this.el.createChild();
53721 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
53724 this.add(region, ret);
53728 case 'TreePanel': // our new panel!
53729 cfg.el = this.el.createChild();
53730 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
53731 this.add(region, ret);
53734 case 'NestedLayoutPanel':
53735 // create a new Layout (which is a Border Layout...
53736 var el = this.el.createChild();
53737 var clayout = cfg.layout;
53739 clayout.items = clayout.items || [];
53740 // replace this exitems with the clayout ones..
53741 xitems = clayout.items;
53744 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
53745 cfg.background = false;
53747 var layout = new Roo.BorderLayout(el, clayout);
53749 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
53750 //console.log('adding nested layout panel ' + cfg.toSource());
53751 this.add(region, ret);
53752 nb = {}; /// find first...
53757 // needs grid and region
53759 //var el = this.getRegion(region).el.createChild();
53760 var el = this.el.createChild();
53761 // create the grid first...
53763 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
53765 if (region == 'center' && this.active ) {
53766 cfg.background = false;
53768 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
53770 this.add(region, ret);
53771 if (cfg.background) {
53772 ret.on('activate', function(gp) {
53773 if (!gp.grid.rendered) {
53788 if (typeof(Roo[cfg.xtype]) != 'undefined') {
53790 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
53791 this.add(region, ret);
53794 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
53798 // GridPanel (grid, cfg)
53801 this.beginUpdate();
53805 Roo.each(xitems, function(i) {
53806 region = nb && i.region ? i.region : false;
53808 var add = ret.addxtype(i);
53811 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
53812 if (!i.background) {
53813 abn[region] = nb[region] ;
53820 // make the last non-background panel active..
53821 //if (nb) { Roo.log(abn); }
53824 for(var r in abn) {
53825 region = this.getRegion(r);
53827 // tried using nb[r], but it does not work..
53829 region.showPanel(abn[r]);
53840 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
53841 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
53842 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
53843 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
53846 var CP = Roo.ContentPanel;
53848 var layout = Roo.BorderLayout.create({
53852 panels: [new CP("north", "North")]
53861 panels: [new CP("west", {title: "West"})]
53870 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
53879 panels: [new CP("south", {title: "South", closable: true})]
53886 preferredTabWidth: 150,
53888 new CP("center1", {title: "Close Me", closable: true}),
53889 new CP("center2", {title: "Center Panel", closable: false})
53894 layout.getRegion("center").showPanel("center1");
53899 Roo.BorderLayout.create = function(config, targetEl){
53900 var layout = new Roo.BorderLayout(targetEl || document.body, config);
53901 layout.beginUpdate();
53902 var regions = Roo.BorderLayout.RegionFactory.validRegions;
53903 for(var j = 0, jlen = regions.length; j < jlen; j++){
53904 var lr = regions[j];
53905 if(layout.regions[lr] && config[lr].panels){
53906 var r = layout.regions[lr];
53907 var ps = config[lr].panels;
53908 layout.addTypedPanels(r, ps);
53911 layout.endUpdate();
53916 Roo.BorderLayout.RegionFactory = {
53918 validRegions : ["north","south","east","west","center"],
53921 create : function(target, mgr, config){
53922 target = target.toLowerCase();
53923 if(config.lightweight || config.basic){
53924 return new Roo.BasicLayoutRegion(mgr, config, target);
53928 return new Roo.NorthLayoutRegion(mgr, config);
53930 return new Roo.SouthLayoutRegion(mgr, config);
53932 return new Roo.EastLayoutRegion(mgr, config);
53934 return new Roo.WestLayoutRegion(mgr, config);
53936 return new Roo.CenterLayoutRegion(mgr, config);
53938 throw 'Layout region "'+target+'" not supported.';
53942 * Ext JS Library 1.1.1
53943 * Copyright(c) 2006-2007, Ext JS, LLC.
53945 * Originally Released Under LGPL - original licence link has changed is not relivant.
53948 * <script type="text/javascript">
53952 * @class Roo.BasicLayoutRegion
53953 * @extends Roo.util.Observable
53954 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
53955 * and does not have a titlebar, tabs or any other features. All it does is size and position
53956 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
53958 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
53960 this.position = pos;
53963 * @scope Roo.BasicLayoutRegion
53967 * @event beforeremove
53968 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
53969 * @param {Roo.LayoutRegion} this
53970 * @param {Roo.ContentPanel} panel The panel
53971 * @param {Object} e The cancel event object
53973 "beforeremove" : true,
53975 * @event invalidated
53976 * Fires when the layout for this region is changed.
53977 * @param {Roo.LayoutRegion} this
53979 "invalidated" : true,
53981 * @event visibilitychange
53982 * Fires when this region is shown or hidden
53983 * @param {Roo.LayoutRegion} this
53984 * @param {Boolean} visibility true or false
53986 "visibilitychange" : true,
53988 * @event paneladded
53989 * Fires when a panel is added.
53990 * @param {Roo.LayoutRegion} this
53991 * @param {Roo.ContentPanel} panel The panel
53993 "paneladded" : true,
53995 * @event panelremoved
53996 * Fires when a panel is removed.
53997 * @param {Roo.LayoutRegion} this
53998 * @param {Roo.ContentPanel} panel The panel
54000 "panelremoved" : true,
54002 * @event beforecollapse
54003 * Fires when this region before collapse.
54004 * @param {Roo.LayoutRegion} this
54006 "beforecollapse" : true,
54009 * Fires when this region is collapsed.
54010 * @param {Roo.LayoutRegion} this
54012 "collapsed" : true,
54015 * Fires when this region is expanded.
54016 * @param {Roo.LayoutRegion} this
54021 * Fires when this region is slid into view.
54022 * @param {Roo.LayoutRegion} this
54024 "slideshow" : true,
54027 * Fires when this region slides out of view.
54028 * @param {Roo.LayoutRegion} this
54030 "slidehide" : true,
54032 * @event panelactivated
54033 * Fires when a panel is activated.
54034 * @param {Roo.LayoutRegion} this
54035 * @param {Roo.ContentPanel} panel The activated panel
54037 "panelactivated" : true,
54040 * Fires when the user resizes this region.
54041 * @param {Roo.LayoutRegion} this
54042 * @param {Number} newSize The new size (width for east/west, height for north/south)
54046 /** A collection of panels in this region. @type Roo.util.MixedCollection */
54047 this.panels = new Roo.util.MixedCollection();
54048 this.panels.getKey = this.getPanelId.createDelegate(this);
54050 this.activePanel = null;
54051 // ensure listeners are added...
54053 if (config.listeners || config.events) {
54054 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
54055 listeners : config.listeners || {},
54056 events : config.events || {}
54060 if(skipConfig !== true){
54061 this.applyConfig(config);
54065 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
54066 getPanelId : function(p){
54070 applyConfig : function(config){
54071 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
54072 this.config = config;
54077 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
54078 * the width, for horizontal (north, south) the height.
54079 * @param {Number} newSize The new width or height
54081 resizeTo : function(newSize){
54082 var el = this.el ? this.el :
54083 (this.activePanel ? this.activePanel.getEl() : null);
54085 switch(this.position){
54088 el.setWidth(newSize);
54089 this.fireEvent("resized", this, newSize);
54093 el.setHeight(newSize);
54094 this.fireEvent("resized", this, newSize);
54100 getBox : function(){
54101 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
54104 getMargins : function(){
54105 return this.margins;
54108 updateBox : function(box){
54110 var el = this.activePanel.getEl();
54111 el.dom.style.left = box.x + "px";
54112 el.dom.style.top = box.y + "px";
54113 this.activePanel.setSize(box.width, box.height);
54117 * Returns the container element for this region.
54118 * @return {Roo.Element}
54120 getEl : function(){
54121 return this.activePanel;
54125 * Returns true if this region is currently visible.
54126 * @return {Boolean}
54128 isVisible : function(){
54129 return this.activePanel ? true : false;
54132 setActivePanel : function(panel){
54133 panel = this.getPanel(panel);
54134 if(this.activePanel && this.activePanel != panel){
54135 this.activePanel.setActiveState(false);
54136 this.activePanel.getEl().setLeftTop(-10000,-10000);
54138 this.activePanel = panel;
54139 panel.setActiveState(true);
54141 panel.setSize(this.box.width, this.box.height);
54143 this.fireEvent("panelactivated", this, panel);
54144 this.fireEvent("invalidated");
54148 * Show the specified panel.
54149 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
54150 * @return {Roo.ContentPanel} The shown panel or null
54152 showPanel : function(panel){
54153 if(panel = this.getPanel(panel)){
54154 this.setActivePanel(panel);
54160 * Get the active panel for this region.
54161 * @return {Roo.ContentPanel} The active panel or null
54163 getActivePanel : function(){
54164 return this.activePanel;
54168 * Add the passed ContentPanel(s)
54169 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
54170 * @return {Roo.ContentPanel} The panel added (if only one was added)
54172 add : function(panel){
54173 if(arguments.length > 1){
54174 for(var i = 0, len = arguments.length; i < len; i++) {
54175 this.add(arguments[i]);
54179 if(this.hasPanel(panel)){
54180 this.showPanel(panel);
54183 var el = panel.getEl();
54184 if(el.dom.parentNode != this.mgr.el.dom){
54185 this.mgr.el.dom.appendChild(el.dom);
54187 if(panel.setRegion){
54188 panel.setRegion(this);
54190 this.panels.add(panel);
54191 el.setStyle("position", "absolute");
54192 if(!panel.background){
54193 this.setActivePanel(panel);
54194 if(this.config.initialSize && this.panels.getCount()==1){
54195 this.resizeTo(this.config.initialSize);
54198 this.fireEvent("paneladded", this, panel);
54203 * Returns true if the panel is in this region.
54204 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
54205 * @return {Boolean}
54207 hasPanel : function(panel){
54208 if(typeof panel == "object"){ // must be panel obj
54209 panel = panel.getId();
54211 return this.getPanel(panel) ? true : false;
54215 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
54216 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
54217 * @param {Boolean} preservePanel Overrides the config preservePanel option
54218 * @return {Roo.ContentPanel} The panel that was removed
54220 remove : function(panel, preservePanel){
54221 panel = this.getPanel(panel);
54226 this.fireEvent("beforeremove", this, panel, e);
54227 if(e.cancel === true){
54230 var panelId = panel.getId();
54231 this.panels.removeKey(panelId);
54236 * Returns the panel specified or null if it's not in this region.
54237 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
54238 * @return {Roo.ContentPanel}
54240 getPanel : function(id){
54241 if(typeof id == "object"){ // must be panel obj
54244 return this.panels.get(id);
54248 * Returns this regions position (north/south/east/west/center).
54251 getPosition: function(){
54252 return this.position;
54256 * Ext JS Library 1.1.1
54257 * Copyright(c) 2006-2007, Ext JS, LLC.
54259 * Originally Released Under LGPL - original licence link has changed is not relivant.
54262 * <script type="text/javascript">
54266 * @class Roo.LayoutRegion
54267 * @extends Roo.BasicLayoutRegion
54268 * This class represents a region in a layout manager.
54269 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
54270 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
54271 * @cfg {Boolean} floatable False to disable floating (defaults to true)
54272 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
54273 * @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})
54274 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
54275 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
54276 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
54277 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
54278 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
54279 * @cfg {String} title The title for the region (overrides panel titles)
54280 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
54281 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
54282 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
54283 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
54284 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
54285 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
54286 * the space available, similar to FireFox 1.5 tabs (defaults to false)
54287 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
54288 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
54289 * @cfg {Boolean} showPin True to show a pin button
54290 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
54291 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
54292 * @cfg {Boolean} disableTabTips True to disable tab tooltips
54293 * @cfg {Number} width For East/West panels
54294 * @cfg {Number} height For North/South panels
54295 * @cfg {Boolean} split To show the splitter
54296 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
54298 Roo.LayoutRegion = function(mgr, config, pos){
54299 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
54300 var dh = Roo.DomHelper;
54301 /** This region's container element
54302 * @type Roo.Element */
54303 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
54304 /** This region's title element
54305 * @type Roo.Element */
54307 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
54308 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
54309 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
54311 this.titleEl.enableDisplayMode();
54312 /** This region's title text element
54313 * @type HTMLElement */
54314 this.titleTextEl = this.titleEl.dom.firstChild;
54315 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
54316 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
54317 this.closeBtn.enableDisplayMode();
54318 this.closeBtn.on("click", this.closeClicked, this);
54319 this.closeBtn.hide();
54321 this.createBody(config);
54322 this.visible = true;
54323 this.collapsed = false;
54325 if(config.hideWhenEmpty){
54327 this.on("paneladded", this.validateVisibility, this);
54328 this.on("panelremoved", this.validateVisibility, this);
54330 this.applyConfig(config);
54333 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
54335 createBody : function(){
54336 /** This region's body element
54337 * @type Roo.Element */
54338 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
54341 applyConfig : function(c){
54342 if(c.collapsible && this.position != "center" && !this.collapsedEl){
54343 var dh = Roo.DomHelper;
54344 if(c.titlebar !== false){
54345 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
54346 this.collapseBtn.on("click", this.collapse, this);
54347 this.collapseBtn.enableDisplayMode();
54349 if(c.showPin === true || this.showPin){
54350 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
54351 this.stickBtn.enableDisplayMode();
54352 this.stickBtn.on("click", this.expand, this);
54353 this.stickBtn.hide();
54356 /** This region's collapsed element
54357 * @type Roo.Element */
54358 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
54359 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
54361 if(c.floatable !== false){
54362 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
54363 this.collapsedEl.on("click", this.collapseClick, this);
54366 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
54367 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
54368 id: "message", unselectable: "on", style:{"float":"left"}});
54369 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
54371 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
54372 this.expandBtn.on("click", this.expand, this);
54374 if(this.collapseBtn){
54375 this.collapseBtn.setVisible(c.collapsible == true);
54377 this.cmargins = c.cmargins || this.cmargins ||
54378 (this.position == "west" || this.position == "east" ?
54379 {top: 0, left: 2, right:2, bottom: 0} :
54380 {top: 2, left: 0, right:0, bottom: 2});
54381 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
54382 this.bottomTabs = c.tabPosition != "top";
54383 this.autoScroll = c.autoScroll || false;
54384 if(this.autoScroll){
54385 this.bodyEl.setStyle("overflow", "auto");
54387 this.bodyEl.setStyle("overflow", "hidden");
54389 //if(c.titlebar !== false){
54390 if((!c.titlebar && !c.title) || c.titlebar === false){
54391 this.titleEl.hide();
54393 this.titleEl.show();
54395 this.titleTextEl.innerHTML = c.title;
54399 this.duration = c.duration || .30;
54400 this.slideDuration = c.slideDuration || .45;
54403 this.collapse(true);
54410 * Returns true if this region is currently visible.
54411 * @return {Boolean}
54413 isVisible : function(){
54414 return this.visible;
54418 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
54419 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
54421 setCollapsedTitle : function(title){
54422 title = title || " ";
54423 if(this.collapsedTitleTextEl){
54424 this.collapsedTitleTextEl.innerHTML = title;
54428 getBox : function(){
54430 if(!this.collapsed){
54431 b = this.el.getBox(false, true);
54433 b = this.collapsedEl.getBox(false, true);
54438 getMargins : function(){
54439 return this.collapsed ? this.cmargins : this.margins;
54442 highlight : function(){
54443 this.el.addClass("x-layout-panel-dragover");
54446 unhighlight : function(){
54447 this.el.removeClass("x-layout-panel-dragover");
54450 updateBox : function(box){
54452 if(!this.collapsed){
54453 this.el.dom.style.left = box.x + "px";
54454 this.el.dom.style.top = box.y + "px";
54455 this.updateBody(box.width, box.height);
54457 this.collapsedEl.dom.style.left = box.x + "px";
54458 this.collapsedEl.dom.style.top = box.y + "px";
54459 this.collapsedEl.setSize(box.width, box.height);
54462 this.tabs.autoSizeTabs();
54466 updateBody : function(w, h){
54468 this.el.setWidth(w);
54469 w -= this.el.getBorderWidth("rl");
54470 if(this.config.adjustments){
54471 w += this.config.adjustments[0];
54475 this.el.setHeight(h);
54476 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
54477 h -= this.el.getBorderWidth("tb");
54478 if(this.config.adjustments){
54479 h += this.config.adjustments[1];
54481 this.bodyEl.setHeight(h);
54483 h = this.tabs.syncHeight(h);
54486 if(this.panelSize){
54487 w = w !== null ? w : this.panelSize.width;
54488 h = h !== null ? h : this.panelSize.height;
54490 if(this.activePanel){
54491 var el = this.activePanel.getEl();
54492 w = w !== null ? w : el.getWidth();
54493 h = h !== null ? h : el.getHeight();
54494 this.panelSize = {width: w, height: h};
54495 this.activePanel.setSize(w, h);
54497 if(Roo.isIE && this.tabs){
54498 this.tabs.el.repaint();
54503 * Returns the container element for this region.
54504 * @return {Roo.Element}
54506 getEl : function(){
54511 * Hides this region.
54514 if(!this.collapsed){
54515 this.el.dom.style.left = "-2000px";
54518 this.collapsedEl.dom.style.left = "-2000px";
54519 this.collapsedEl.hide();
54521 this.visible = false;
54522 this.fireEvent("visibilitychange", this, false);
54526 * Shows this region if it was previously hidden.
54529 if(!this.collapsed){
54532 this.collapsedEl.show();
54534 this.visible = true;
54535 this.fireEvent("visibilitychange", this, true);
54538 closeClicked : function(){
54539 if(this.activePanel){
54540 this.remove(this.activePanel);
54544 collapseClick : function(e){
54546 e.stopPropagation();
54549 e.stopPropagation();
54555 * Collapses this region.
54556 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
54558 collapse : function(skipAnim, skipCheck){
54559 if(this.collapsed) {
54563 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
54565 this.collapsed = true;
54567 this.split.el.hide();
54569 if(this.config.animate && skipAnim !== true){
54570 this.fireEvent("invalidated", this);
54571 this.animateCollapse();
54573 this.el.setLocation(-20000,-20000);
54575 this.collapsedEl.show();
54576 this.fireEvent("collapsed", this);
54577 this.fireEvent("invalidated", this);
54583 animateCollapse : function(){
54588 * Expands this region if it was previously collapsed.
54589 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
54590 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
54592 expand : function(e, skipAnim){
54594 e.stopPropagation();
54596 if(!this.collapsed || this.el.hasActiveFx()) {
54600 this.afterSlideIn();
54603 this.collapsed = false;
54604 if(this.config.animate && skipAnim !== true){
54605 this.animateExpand();
54609 this.split.el.show();
54611 this.collapsedEl.setLocation(-2000,-2000);
54612 this.collapsedEl.hide();
54613 this.fireEvent("invalidated", this);
54614 this.fireEvent("expanded", this);
54618 animateExpand : function(){
54622 initTabs : function()
54624 this.bodyEl.setStyle("overflow", "hidden");
54625 var ts = new Roo.TabPanel(
54628 tabPosition: this.bottomTabs ? 'bottom' : 'top',
54629 disableTooltips: this.config.disableTabTips,
54630 toolbar : this.config.toolbar
54633 if(this.config.hideTabs){
54634 ts.stripWrap.setDisplayed(false);
54637 ts.resizeTabs = this.config.resizeTabs === true;
54638 ts.minTabWidth = this.config.minTabWidth || 40;
54639 ts.maxTabWidth = this.config.maxTabWidth || 250;
54640 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
54641 ts.monitorResize = false;
54642 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
54643 ts.bodyEl.addClass('x-layout-tabs-body');
54644 this.panels.each(this.initPanelAsTab, this);
54647 initPanelAsTab : function(panel){
54648 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
54649 this.config.closeOnTab && panel.isClosable());
54650 if(panel.tabTip !== undefined){
54651 ti.setTooltip(panel.tabTip);
54653 ti.on("activate", function(){
54654 this.setActivePanel(panel);
54656 if(this.config.closeOnTab){
54657 ti.on("beforeclose", function(t, e){
54659 this.remove(panel);
54665 updatePanelTitle : function(panel, title){
54666 if(this.activePanel == panel){
54667 this.updateTitle(title);
54670 var ti = this.tabs.getTab(panel.getEl().id);
54672 if(panel.tabTip !== undefined){
54673 ti.setTooltip(panel.tabTip);
54678 updateTitle : function(title){
54679 if(this.titleTextEl && !this.config.title){
54680 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
54684 setActivePanel : function(panel){
54685 panel = this.getPanel(panel);
54686 if(this.activePanel && this.activePanel != panel){
54687 this.activePanel.setActiveState(false);
54689 this.activePanel = panel;
54690 panel.setActiveState(true);
54691 if(this.panelSize){
54692 panel.setSize(this.panelSize.width, this.panelSize.height);
54695 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
54697 this.updateTitle(panel.getTitle());
54699 this.fireEvent("invalidated", this);
54701 this.fireEvent("panelactivated", this, panel);
54705 * Shows the specified panel.
54706 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
54707 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
54709 showPanel : function(panel)
54711 panel = this.getPanel(panel);
54714 var tab = this.tabs.getTab(panel.getEl().id);
54715 if(tab.isHidden()){
54716 this.tabs.unhideTab(tab.id);
54720 this.setActivePanel(panel);
54727 * Get the active panel for this region.
54728 * @return {Roo.ContentPanel} The active panel or null
54730 getActivePanel : function(){
54731 return this.activePanel;
54734 validateVisibility : function(){
54735 if(this.panels.getCount() < 1){
54736 this.updateTitle(" ");
54737 this.closeBtn.hide();
54740 if(!this.isVisible()){
54747 * Adds the passed ContentPanel(s) to this region.
54748 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
54749 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
54751 add : function(panel){
54752 if(arguments.length > 1){
54753 for(var i = 0, len = arguments.length; i < len; i++) {
54754 this.add(arguments[i]);
54758 if(this.hasPanel(panel)){
54759 this.showPanel(panel);
54762 panel.setRegion(this);
54763 this.panels.add(panel);
54764 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
54765 this.bodyEl.dom.appendChild(panel.getEl().dom);
54766 if(panel.background !== true){
54767 this.setActivePanel(panel);
54769 this.fireEvent("paneladded", this, panel);
54775 this.initPanelAsTab(panel);
54777 if(panel.background !== true){
54778 this.tabs.activate(panel.getEl().id);
54780 this.fireEvent("paneladded", this, panel);
54785 * Hides the tab for the specified panel.
54786 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
54788 hidePanel : function(panel){
54789 if(this.tabs && (panel = this.getPanel(panel))){
54790 this.tabs.hideTab(panel.getEl().id);
54795 * Unhides the tab for a previously hidden panel.
54796 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
54798 unhidePanel : function(panel){
54799 if(this.tabs && (panel = this.getPanel(panel))){
54800 this.tabs.unhideTab(panel.getEl().id);
54804 clearPanels : function(){
54805 while(this.panels.getCount() > 0){
54806 this.remove(this.panels.first());
54811 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
54812 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
54813 * @param {Boolean} preservePanel Overrides the config preservePanel option
54814 * @return {Roo.ContentPanel} The panel that was removed
54816 remove : function(panel, preservePanel){
54817 panel = this.getPanel(panel);
54822 this.fireEvent("beforeremove", this, panel, e);
54823 if(e.cancel === true){
54826 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
54827 var panelId = panel.getId();
54828 this.panels.removeKey(panelId);
54830 document.body.appendChild(panel.getEl().dom);
54833 this.tabs.removeTab(panel.getEl().id);
54834 }else if (!preservePanel){
54835 this.bodyEl.dom.removeChild(panel.getEl().dom);
54837 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
54838 var p = this.panels.first();
54839 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
54840 tempEl.appendChild(p.getEl().dom);
54841 this.bodyEl.update("");
54842 this.bodyEl.dom.appendChild(p.getEl().dom);
54844 this.updateTitle(p.getTitle());
54846 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
54847 this.setActivePanel(p);
54849 panel.setRegion(null);
54850 if(this.activePanel == panel){
54851 this.activePanel = null;
54853 if(this.config.autoDestroy !== false && preservePanel !== true){
54854 try{panel.destroy();}catch(e){}
54856 this.fireEvent("panelremoved", this, panel);
54861 * Returns the TabPanel component used by this region
54862 * @return {Roo.TabPanel}
54864 getTabs : function(){
54868 createTool : function(parentEl, className){
54869 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
54870 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
54871 btn.addClassOnOver("x-layout-tools-button-over");
54876 * Ext JS Library 1.1.1
54877 * Copyright(c) 2006-2007, Ext JS, LLC.
54879 * Originally Released Under LGPL - original licence link has changed is not relivant.
54882 * <script type="text/javascript">
54888 * @class Roo.SplitLayoutRegion
54889 * @extends Roo.LayoutRegion
54890 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
54892 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
54893 this.cursor = cursor;
54894 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
54897 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
54898 splitTip : "Drag to resize.",
54899 collapsibleSplitTip : "Drag to resize. Double click to hide.",
54900 useSplitTips : false,
54902 applyConfig : function(config){
54903 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
54906 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
54907 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
54908 /** The SplitBar for this region
54909 * @type Roo.SplitBar */
54910 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
54911 this.split.on("moved", this.onSplitMove, this);
54912 this.split.useShim = config.useShim === true;
54913 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
54914 if(this.useSplitTips){
54915 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
54917 if(config.collapsible){
54918 this.split.el.on("dblclick", this.collapse, this);
54921 if(typeof config.minSize != "undefined"){
54922 this.split.minSize = config.minSize;
54924 if(typeof config.maxSize != "undefined"){
54925 this.split.maxSize = config.maxSize;
54927 if(config.hideWhenEmpty || config.hidden || config.collapsed){
54928 this.hideSplitter();
54933 getHMaxSize : function(){
54934 var cmax = this.config.maxSize || 10000;
54935 var center = this.mgr.getRegion("center");
54936 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
54939 getVMaxSize : function(){
54940 var cmax = this.config.maxSize || 10000;
54941 var center = this.mgr.getRegion("center");
54942 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
54945 onSplitMove : function(split, newSize){
54946 this.fireEvent("resized", this, newSize);
54950 * Returns the {@link Roo.SplitBar} for this region.
54951 * @return {Roo.SplitBar}
54953 getSplitBar : function(){
54958 this.hideSplitter();
54959 Roo.SplitLayoutRegion.superclass.hide.call(this);
54962 hideSplitter : function(){
54964 this.split.el.setLocation(-2000,-2000);
54965 this.split.el.hide();
54971 this.split.el.show();
54973 Roo.SplitLayoutRegion.superclass.show.call(this);
54976 beforeSlide: function(){
54977 if(Roo.isGecko){// firefox overflow auto bug workaround
54978 this.bodyEl.clip();
54980 this.tabs.bodyEl.clip();
54982 if(this.activePanel){
54983 this.activePanel.getEl().clip();
54985 if(this.activePanel.beforeSlide){
54986 this.activePanel.beforeSlide();
54992 afterSlide : function(){
54993 if(Roo.isGecko){// firefox overflow auto bug workaround
54994 this.bodyEl.unclip();
54996 this.tabs.bodyEl.unclip();
54998 if(this.activePanel){
54999 this.activePanel.getEl().unclip();
55000 if(this.activePanel.afterSlide){
55001 this.activePanel.afterSlide();
55007 initAutoHide : function(){
55008 if(this.autoHide !== false){
55009 if(!this.autoHideHd){
55010 var st = new Roo.util.DelayedTask(this.slideIn, this);
55011 this.autoHideHd = {
55012 "mouseout": function(e){
55013 if(!e.within(this.el, true)){
55017 "mouseover" : function(e){
55023 this.el.on(this.autoHideHd);
55027 clearAutoHide : function(){
55028 if(this.autoHide !== false){
55029 this.el.un("mouseout", this.autoHideHd.mouseout);
55030 this.el.un("mouseover", this.autoHideHd.mouseover);
55034 clearMonitor : function(){
55035 Roo.get(document).un("click", this.slideInIf, this);
55038 // these names are backwards but not changed for compat
55039 slideOut : function(){
55040 if(this.isSlid || this.el.hasActiveFx()){
55043 this.isSlid = true;
55044 if(this.collapseBtn){
55045 this.collapseBtn.hide();
55047 this.closeBtnState = this.closeBtn.getStyle('display');
55048 this.closeBtn.hide();
55050 this.stickBtn.show();
55053 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
55054 this.beforeSlide();
55055 this.el.setStyle("z-index", 10001);
55056 this.el.slideIn(this.getSlideAnchor(), {
55057 callback: function(){
55059 this.initAutoHide();
55060 Roo.get(document).on("click", this.slideInIf, this);
55061 this.fireEvent("slideshow", this);
55068 afterSlideIn : function(){
55069 this.clearAutoHide();
55070 this.isSlid = false;
55071 this.clearMonitor();
55072 this.el.setStyle("z-index", "");
55073 if(this.collapseBtn){
55074 this.collapseBtn.show();
55076 this.closeBtn.setStyle('display', this.closeBtnState);
55078 this.stickBtn.hide();
55080 this.fireEvent("slidehide", this);
55083 slideIn : function(cb){
55084 if(!this.isSlid || this.el.hasActiveFx()){
55088 this.isSlid = false;
55089 this.beforeSlide();
55090 this.el.slideOut(this.getSlideAnchor(), {
55091 callback: function(){
55092 this.el.setLeftTop(-10000, -10000);
55094 this.afterSlideIn();
55102 slideInIf : function(e){
55103 if(!e.within(this.el)){
55108 animateCollapse : function(){
55109 this.beforeSlide();
55110 this.el.setStyle("z-index", 20000);
55111 var anchor = this.getSlideAnchor();
55112 this.el.slideOut(anchor, {
55113 callback : function(){
55114 this.el.setStyle("z-index", "");
55115 this.collapsedEl.slideIn(anchor, {duration:.3});
55117 this.el.setLocation(-10000,-10000);
55119 this.fireEvent("collapsed", this);
55126 animateExpand : function(){
55127 this.beforeSlide();
55128 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
55129 this.el.setStyle("z-index", 20000);
55130 this.collapsedEl.hide({
55133 this.el.slideIn(this.getSlideAnchor(), {
55134 callback : function(){
55135 this.el.setStyle("z-index", "");
55138 this.split.el.show();
55140 this.fireEvent("invalidated", this);
55141 this.fireEvent("expanded", this);
55169 getAnchor : function(){
55170 return this.anchors[this.position];
55173 getCollapseAnchor : function(){
55174 return this.canchors[this.position];
55177 getSlideAnchor : function(){
55178 return this.sanchors[this.position];
55181 getAlignAdj : function(){
55182 var cm = this.cmargins;
55183 switch(this.position){
55199 getExpandAdj : function(){
55200 var c = this.collapsedEl, cm = this.cmargins;
55201 switch(this.position){
55203 return [-(cm.right+c.getWidth()+cm.left), 0];
55206 return [cm.right+c.getWidth()+cm.left, 0];
55209 return [0, -(cm.top+cm.bottom+c.getHeight())];
55212 return [0, cm.top+cm.bottom+c.getHeight()];
55218 * Ext JS Library 1.1.1
55219 * Copyright(c) 2006-2007, Ext JS, LLC.
55221 * Originally Released Under LGPL - original licence link has changed is not relivant.
55224 * <script type="text/javascript">
55227 * These classes are private internal classes
55229 Roo.CenterLayoutRegion = function(mgr, config){
55230 Roo.LayoutRegion.call(this, mgr, config, "center");
55231 this.visible = true;
55232 this.minWidth = config.minWidth || 20;
55233 this.minHeight = config.minHeight || 20;
55236 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
55238 // center panel can't be hidden
55242 // center panel can't be hidden
55245 getMinWidth: function(){
55246 return this.minWidth;
55249 getMinHeight: function(){
55250 return this.minHeight;
55255 Roo.NorthLayoutRegion = function(mgr, config){
55256 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
55258 this.split.placement = Roo.SplitBar.TOP;
55259 this.split.orientation = Roo.SplitBar.VERTICAL;
55260 this.split.el.addClass("x-layout-split-v");
55262 var size = config.initialSize || config.height;
55263 if(typeof size != "undefined"){
55264 this.el.setHeight(size);
55267 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
55268 orientation: Roo.SplitBar.VERTICAL,
55269 getBox : function(){
55270 if(this.collapsed){
55271 return this.collapsedEl.getBox();
55273 var box = this.el.getBox();
55275 box.height += this.split.el.getHeight();
55280 updateBox : function(box){
55281 if(this.split && !this.collapsed){
55282 box.height -= this.split.el.getHeight();
55283 this.split.el.setLeft(box.x);
55284 this.split.el.setTop(box.y+box.height);
55285 this.split.el.setWidth(box.width);
55287 if(this.collapsed){
55288 this.updateBody(box.width, null);
55290 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55294 Roo.SouthLayoutRegion = function(mgr, config){
55295 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
55297 this.split.placement = Roo.SplitBar.BOTTOM;
55298 this.split.orientation = Roo.SplitBar.VERTICAL;
55299 this.split.el.addClass("x-layout-split-v");
55301 var size = config.initialSize || config.height;
55302 if(typeof size != "undefined"){
55303 this.el.setHeight(size);
55306 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
55307 orientation: Roo.SplitBar.VERTICAL,
55308 getBox : function(){
55309 if(this.collapsed){
55310 return this.collapsedEl.getBox();
55312 var box = this.el.getBox();
55314 var sh = this.split.el.getHeight();
55321 updateBox : function(box){
55322 if(this.split && !this.collapsed){
55323 var sh = this.split.el.getHeight();
55326 this.split.el.setLeft(box.x);
55327 this.split.el.setTop(box.y-sh);
55328 this.split.el.setWidth(box.width);
55330 if(this.collapsed){
55331 this.updateBody(box.width, null);
55333 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55337 Roo.EastLayoutRegion = function(mgr, config){
55338 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
55340 this.split.placement = Roo.SplitBar.RIGHT;
55341 this.split.orientation = Roo.SplitBar.HORIZONTAL;
55342 this.split.el.addClass("x-layout-split-h");
55344 var size = config.initialSize || config.width;
55345 if(typeof size != "undefined"){
55346 this.el.setWidth(size);
55349 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
55350 orientation: Roo.SplitBar.HORIZONTAL,
55351 getBox : function(){
55352 if(this.collapsed){
55353 return this.collapsedEl.getBox();
55355 var box = this.el.getBox();
55357 var sw = this.split.el.getWidth();
55364 updateBox : function(box){
55365 if(this.split && !this.collapsed){
55366 var sw = this.split.el.getWidth();
55368 this.split.el.setLeft(box.x);
55369 this.split.el.setTop(box.y);
55370 this.split.el.setHeight(box.height);
55373 if(this.collapsed){
55374 this.updateBody(null, box.height);
55376 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55380 Roo.WestLayoutRegion = function(mgr, config){
55381 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
55383 this.split.placement = Roo.SplitBar.LEFT;
55384 this.split.orientation = Roo.SplitBar.HORIZONTAL;
55385 this.split.el.addClass("x-layout-split-h");
55387 var size = config.initialSize || config.width;
55388 if(typeof size != "undefined"){
55389 this.el.setWidth(size);
55392 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
55393 orientation: Roo.SplitBar.HORIZONTAL,
55394 getBox : function(){
55395 if(this.collapsed){
55396 return this.collapsedEl.getBox();
55398 var box = this.el.getBox();
55400 box.width += this.split.el.getWidth();
55405 updateBox : function(box){
55406 if(this.split && !this.collapsed){
55407 var sw = this.split.el.getWidth();
55409 this.split.el.setLeft(box.x+box.width);
55410 this.split.el.setTop(box.y);
55411 this.split.el.setHeight(box.height);
55413 if(this.collapsed){
55414 this.updateBody(null, box.height);
55416 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55421 * Ext JS Library 1.1.1
55422 * Copyright(c) 2006-2007, Ext JS, LLC.
55424 * Originally Released Under LGPL - original licence link has changed is not relivant.
55427 * <script type="text/javascript">
55432 * Private internal class for reading and applying state
55434 Roo.LayoutStateManager = function(layout){
55435 // default empty state
55444 Roo.LayoutStateManager.prototype = {
55445 init : function(layout, provider){
55446 this.provider = provider;
55447 var state = provider.get(layout.id+"-layout-state");
55449 var wasUpdating = layout.isUpdating();
55451 layout.beginUpdate();
55453 for(var key in state){
55454 if(typeof state[key] != "function"){
55455 var rstate = state[key];
55456 var r = layout.getRegion(key);
55459 r.resizeTo(rstate.size);
55461 if(rstate.collapsed == true){
55464 r.expand(null, true);
55470 layout.endUpdate();
55472 this.state = state;
55474 this.layout = layout;
55475 layout.on("regionresized", this.onRegionResized, this);
55476 layout.on("regioncollapsed", this.onRegionCollapsed, this);
55477 layout.on("regionexpanded", this.onRegionExpanded, this);
55480 storeState : function(){
55481 this.provider.set(this.layout.id+"-layout-state", this.state);
55484 onRegionResized : function(region, newSize){
55485 this.state[region.getPosition()].size = newSize;
55489 onRegionCollapsed : function(region){
55490 this.state[region.getPosition()].collapsed = true;
55494 onRegionExpanded : function(region){
55495 this.state[region.getPosition()].collapsed = false;
55500 * Ext JS Library 1.1.1
55501 * Copyright(c) 2006-2007, Ext JS, LLC.
55503 * Originally Released Under LGPL - original licence link has changed is not relivant.
55506 * <script type="text/javascript">
55509 * @class Roo.ContentPanel
55510 * @extends Roo.util.Observable
55511 * @children Roo.form.Form Roo.JsonView Roo.View
55512 * @parent Roo.BorderLayout Roo.LayoutDialog builder-top
55513 * A basic ContentPanel element.
55514 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
55515 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
55516 * @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
55517 * @cfg {Boolean} closable True if the panel can be closed/removed
55518 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
55519 * @cfg {String|HTMLElement|Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
55520 * @cfg {Roo.Toolbar} toolbar A toolbar for this panel
55521 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
55522 * @cfg {String} title The title for this panel
55523 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
55524 * @cfg {String} url Calls {@link #setUrl} with this value
55525 * @cfg {String} region [required] (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
55526 * @cfg {String|Object} params When used with {@link #url}, calls {@link #setUrl} with this value
55527 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
55528 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
55529 * @cfg {String} style Extra style to add to the content panel
55530 * @cfg {Roo.menu.Menu} menu popup menu
55533 * Create a new ContentPanel.
55534 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
55535 * @param {String/Object} config A string to set only the title or a config object
55536 * @param {String} content (optional) Set the HTML content for this panel
55537 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
55539 Roo.ContentPanel = function(el, config, content){
55543 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
55547 if (config && config.parentLayout) {
55548 el = config.parentLayout.el.createChild();
55551 if(el.autoCreate){ // xtype is available if this is called from factory
55555 this.el = Roo.get(el);
55556 if(!this.el && config && config.autoCreate){
55557 if(typeof config.autoCreate == "object"){
55558 if(!config.autoCreate.id){
55559 config.autoCreate.id = config.id||el;
55561 this.el = Roo.DomHelper.append(document.body,
55562 config.autoCreate, true);
55564 this.el = Roo.DomHelper.append(document.body,
55565 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
55570 this.closable = false;
55571 this.loaded = false;
55572 this.active = false;
55573 if(typeof config == "string"){
55574 this.title = config;
55576 Roo.apply(this, config);
55579 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
55580 this.wrapEl = this.el.wrap();
55581 this.toolbar.container = this.el.insertSibling(false, 'before');
55582 this.toolbar = new Roo.Toolbar(this.toolbar);
55585 // xtype created footer. - not sure if will work as we normally have to render first..
55586 if (this.footer && !this.footer.el && this.footer.xtype) {
55587 if (!this.wrapEl) {
55588 this.wrapEl = this.el.wrap();
55591 this.footer.container = this.wrapEl.createChild();
55593 this.footer = Roo.factory(this.footer, Roo);
55598 this.resizeEl = Roo.get(this.resizeEl, true);
55600 this.resizeEl = this.el;
55602 // handle view.xtype
55610 * Fires when this panel is activated.
55611 * @param {Roo.ContentPanel} this
55615 * @event deactivate
55616 * Fires when this panel is activated.
55617 * @param {Roo.ContentPanel} this
55619 "deactivate" : true,
55623 * Fires when this panel is resized if fitToFrame is true.
55624 * @param {Roo.ContentPanel} this
55625 * @param {Number} width The width after any component adjustments
55626 * @param {Number} height The height after any component adjustments
55632 * Fires when this tab is created
55633 * @param {Roo.ContentPanel} this
55643 if(this.autoScroll){
55644 this.resizeEl.setStyle("overflow", "auto");
55646 // fix randome scrolling
55647 this.el.on('scroll', function() {
55648 Roo.log('fix random scolling');
55649 this.scrollTo('top',0);
55652 content = content || this.content;
55654 this.setContent(content);
55656 if(config && config.url){
55657 this.setUrl(this.url, this.params, this.loadOnce);
55662 Roo.ContentPanel.superclass.constructor.call(this);
55664 if (this.view && typeof(this.view.xtype) != 'undefined') {
55665 this.view.el = this.el.appendChild(document.createElement("div"));
55666 this.view = Roo.factory(this.view);
55667 this.view.render && this.view.render(false, '');
55671 this.fireEvent('render', this);
55674 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
55676 setRegion : function(region){
55677 this.region = region;
55679 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
55681 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
55686 * Returns the toolbar for this Panel if one was configured.
55687 * @return {Roo.Toolbar}
55689 getToolbar : function(){
55690 return this.toolbar;
55693 setActiveState : function(active){
55694 this.active = active;
55696 this.fireEvent("deactivate", this);
55698 this.fireEvent("activate", this);
55702 * Updates this panel's element
55703 * @param {String} content The new content
55704 * @param {Boolean} loadScripts (optional) true to look for and process scripts
55706 setContent : function(content, loadScripts){
55707 this.el.update(content, loadScripts);
55710 ignoreResize : function(w, h){
55711 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
55714 this.lastSize = {width: w, height: h};
55719 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
55720 * @return {Roo.UpdateManager} The UpdateManager
55722 getUpdateManager : function(){
55723 return this.el.getUpdateManager();
55726 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
55727 * @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:
55730 url: "your-url.php",
55731 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
55732 callback: yourFunction,
55733 scope: yourObject, //(optional scope)
55736 text: "Loading...",
55741 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
55742 * 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.
55743 * @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}
55744 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
55745 * @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.
55746 * @return {Roo.ContentPanel} this
55749 var um = this.el.getUpdateManager();
55750 um.update.apply(um, arguments);
55756 * 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.
55757 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
55758 * @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)
55759 * @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)
55760 * @return {Roo.UpdateManager} The UpdateManager
55762 setUrl : function(url, params, loadOnce){
55763 if(this.refreshDelegate){
55764 this.removeListener("activate", this.refreshDelegate);
55766 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
55767 this.on("activate", this.refreshDelegate);
55768 return this.el.getUpdateManager();
55771 _handleRefresh : function(url, params, loadOnce){
55772 if(!loadOnce || !this.loaded){
55773 var updater = this.el.getUpdateManager();
55774 updater.update(url, params, this._setLoaded.createDelegate(this));
55778 _setLoaded : function(){
55779 this.loaded = true;
55783 * Returns this panel's id
55786 getId : function(){
55791 * Returns this panel's element - used by regiosn to add.
55792 * @return {Roo.Element}
55794 getEl : function(){
55795 return this.wrapEl || this.el;
55798 adjustForComponents : function(width, height)
55800 //Roo.log('adjustForComponents ');
55801 if(this.resizeEl != this.el){
55802 width -= this.el.getFrameWidth('lr');
55803 height -= this.el.getFrameWidth('tb');
55806 var te = this.toolbar.getEl();
55807 height -= te.getHeight();
55808 te.setWidth(width);
55811 var te = this.footer.getEl();
55812 //Roo.log("footer:" + te.getHeight());
55814 height -= te.getHeight();
55815 te.setWidth(width);
55819 if(this.adjustments){
55820 width += this.adjustments[0];
55821 height += this.adjustments[1];
55823 return {"width": width, "height": height};
55826 setSize : function(width, height){
55827 if(this.fitToFrame && !this.ignoreResize(width, height)){
55828 if(this.fitContainer && this.resizeEl != this.el){
55829 this.el.setSize(width, height);
55831 var size = this.adjustForComponents(width, height);
55832 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
55833 this.fireEvent('resize', this, size.width, size.height);
55838 * Returns this panel's title
55841 getTitle : function(){
55846 * Set this panel's title
55847 * @param {String} title
55849 setTitle : function(title){
55850 this.title = title;
55852 this.region.updatePanelTitle(this, title);
55857 * Returns true is this panel was configured to be closable
55858 * @return {Boolean}
55860 isClosable : function(){
55861 return this.closable;
55864 beforeSlide : function(){
55866 this.resizeEl.clip();
55869 afterSlide : function(){
55871 this.resizeEl.unclip();
55875 * Force a content refresh from the URL specified in the {@link #setUrl} method.
55876 * Will fail silently if the {@link #setUrl} method has not been called.
55877 * This does not activate the panel, just updates its content.
55879 refresh : function(){
55880 if(this.refreshDelegate){
55881 this.loaded = false;
55882 this.refreshDelegate();
55887 * Destroys this panel
55889 destroy : function(){
55890 this.el.removeAllListeners();
55891 var tempEl = document.createElement("span");
55892 tempEl.appendChild(this.el.dom);
55893 tempEl.innerHTML = "";
55899 * form - if the content panel contains a form - this is a reference to it.
55900 * @type {Roo.form.Form}
55904 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
55905 * This contains a reference to it.
55911 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
55921 * @param {Object} cfg Xtype definition of item to add.
55924 addxtype : function(cfg) {
55926 if (cfg.xtype.match(/^Form$/)) {
55929 //if (this.footer) {
55930 // el = this.footer.container.insertSibling(false, 'before');
55932 el = this.el.createChild();
55935 this.form = new Roo.form.Form(cfg);
55938 if ( this.form.allItems.length) {
55939 this.form.render(el.dom);
55943 // should only have one of theses..
55944 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
55945 // views.. should not be just added - used named prop 'view''
55947 cfg.el = this.el.appendChild(document.createElement("div"));
55950 var ret = new Roo.factory(cfg);
55952 ret.render && ret.render(false, ''); // render blank..
55961 * @class Roo.GridPanel
55962 * @extends Roo.ContentPanel
55964 * Create a new GridPanel.
55965 * @param {Roo.grid.Grid} grid The grid for this panel
55966 * @param {String/Object} config A string to set only the panel's title, or a config object
55968 Roo.GridPanel = function(grid, config){
55971 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
55972 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
55974 this.wrapper.dom.appendChild(grid.getGridEl().dom);
55976 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
55979 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
55981 // xtype created footer. - not sure if will work as we normally have to render first..
55982 if (this.footer && !this.footer.el && this.footer.xtype) {
55984 this.footer.container = this.grid.getView().getFooterPanel(true);
55985 this.footer.dataSource = this.grid.dataSource;
55986 this.footer = Roo.factory(this.footer, Roo);
55990 grid.monitorWindowResize = false; // turn off autosizing
55991 grid.autoHeight = false;
55992 grid.autoWidth = false;
55994 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
55997 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
55998 getId : function(){
55999 return this.grid.id;
56003 * Returns the grid for this panel
56004 * @return {Roo.grid.Grid}
56006 getGrid : function(){
56010 setSize : function(width, height){
56011 if(!this.ignoreResize(width, height)){
56012 var grid = this.grid;
56013 var size = this.adjustForComponents(width, height);
56014 grid.getGridEl().setSize(size.width, size.height);
56019 beforeSlide : function(){
56020 this.grid.getView().scroller.clip();
56023 afterSlide : function(){
56024 this.grid.getView().scroller.unclip();
56027 destroy : function(){
56028 this.grid.destroy();
56030 Roo.GridPanel.superclass.destroy.call(this);
56036 * @class Roo.NestedLayoutPanel
56037 * @extends Roo.ContentPanel
56039 * Create a new NestedLayoutPanel.
56042 * @param {Roo.BorderLayout} layout [required] The layout for this panel
56043 * @param {String/Object} config A string to set only the title or a config object
56045 Roo.NestedLayoutPanel = function(layout, config)
56047 // construct with only one argument..
56048 /* FIXME - implement nicer consturctors
56049 if (layout.layout) {
56051 layout = config.layout;
56052 delete config.layout;
56054 if (layout.xtype && !layout.getEl) {
56055 // then layout needs constructing..
56056 layout = Roo.factory(layout, Roo);
56061 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
56063 layout.monitorWindowResize = false; // turn off autosizing
56064 this.layout = layout;
56065 this.layout.getEl().addClass("x-layout-nested-layout");
56072 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
56074 setSize : function(width, height){
56075 if(!this.ignoreResize(width, height)){
56076 var size = this.adjustForComponents(width, height);
56077 var el = this.layout.getEl();
56078 el.setSize(size.width, size.height);
56079 var touch = el.dom.offsetWidth;
56080 this.layout.layout();
56081 // ie requires a double layout on the first pass
56082 if(Roo.isIE && !this.initialized){
56083 this.initialized = true;
56084 this.layout.layout();
56089 // activate all subpanels if not currently active..
56091 setActiveState : function(active){
56092 this.active = active;
56094 this.fireEvent("deactivate", this);
56098 this.fireEvent("activate", this);
56099 // not sure if this should happen before or after..
56100 if (!this.layout) {
56101 return; // should not happen..
56104 for (var r in this.layout.regions) {
56105 reg = this.layout.getRegion(r);
56106 if (reg.getActivePanel()) {
56107 //reg.showPanel(reg.getActivePanel()); // force it to activate..
56108 reg.setActivePanel(reg.getActivePanel());
56111 if (!reg.panels.length) {
56114 reg.showPanel(reg.getPanel(0));
56123 * Returns the nested BorderLayout for this panel
56124 * @return {Roo.BorderLayout}
56126 getLayout : function(){
56127 return this.layout;
56131 * Adds a xtype elements to the layout of the nested panel
56135 xtype : 'ContentPanel',
56142 xtype : 'NestedLayoutPanel',
56148 items : [ ... list of content panels or nested layout panels.. ]
56152 * @param {Object} cfg Xtype definition of item to add.
56154 addxtype : function(cfg) {
56155 return this.layout.addxtype(cfg);
56160 Roo.ScrollPanel = function(el, config, content){
56161 config = config || {};
56162 config.fitToFrame = true;
56163 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
56165 this.el.dom.style.overflow = "hidden";
56166 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
56167 this.el.removeClass("x-layout-inactive-content");
56168 this.el.on("mousewheel", this.onWheel, this);
56170 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
56171 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
56172 up.unselectable(); down.unselectable();
56173 up.on("click", this.scrollUp, this);
56174 down.on("click", this.scrollDown, this);
56175 up.addClassOnOver("x-scroller-btn-over");
56176 down.addClassOnOver("x-scroller-btn-over");
56177 up.addClassOnClick("x-scroller-btn-click");
56178 down.addClassOnClick("x-scroller-btn-click");
56179 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
56181 this.resizeEl = this.el;
56182 this.el = wrap; this.up = up; this.down = down;
56185 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
56187 wheelIncrement : 5,
56188 scrollUp : function(){
56189 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
56192 scrollDown : function(){
56193 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
56196 afterScroll : function(){
56197 var el = this.resizeEl;
56198 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
56199 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
56200 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
56203 setSize : function(){
56204 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
56205 this.afterScroll();
56208 onWheel : function(e){
56209 var d = e.getWheelDelta();
56210 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
56211 this.afterScroll();
56215 setContent : function(content, loadScripts){
56216 this.resizeEl.update(content, loadScripts);
56224 * @class Roo.TreePanel
56225 * @extends Roo.ContentPanel
56226 * Treepanel component
56229 * Create a new TreePanel. - defaults to fit/scoll contents.
56230 * @param {String/Object} config A string to set only the panel's title, or a config object
56232 Roo.TreePanel = function(config){
56233 var el = config.el;
56234 var tree = config.tree;
56235 delete config.tree;
56236 delete config.el; // hopefull!
56238 // wrapper for IE7 strict & safari scroll issue
56240 var treeEl = el.createChild();
56241 config.resizeEl = treeEl;
56245 Roo.TreePanel.superclass.constructor.call(this, el, config);
56248 this.tree = new Roo.tree.TreePanel(treeEl , tree);
56249 //console.log(tree);
56250 this.on('activate', function()
56252 if (this.tree.rendered) {
56255 //console.log('render tree');
56256 this.tree.render();
56258 // this should not be needed.. - it's actually the 'el' that resizes?
56259 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
56261 //this.on('resize', function (cp, w, h) {
56262 // this.tree.innerCt.setWidth(w);
56263 // this.tree.innerCt.setHeight(h);
56264 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
56271 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
56275 * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
56293 * Ext JS Library 1.1.1
56294 * Copyright(c) 2006-2007, Ext JS, LLC.
56296 * Originally Released Under LGPL - original licence link has changed is not relivant.
56299 * <script type="text/javascript">
56304 * @class Roo.ReaderLayout
56305 * @extends Roo.BorderLayout
56306 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
56307 * center region containing two nested regions (a top one for a list view and one for item preview below),
56308 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
56309 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
56310 * expedites the setup of the overall layout and regions for this common application style.
56313 var reader = new Roo.ReaderLayout();
56314 var CP = Roo.ContentPanel; // shortcut for adding
56316 reader.beginUpdate();
56317 reader.add("north", new CP("north", "North"));
56318 reader.add("west", new CP("west", {title: "West"}));
56319 reader.add("east", new CP("east", {title: "East"}));
56321 reader.regions.listView.add(new CP("listView", "List"));
56322 reader.regions.preview.add(new CP("preview", "Preview"));
56323 reader.endUpdate();
56326 * Create a new ReaderLayout
56327 * @param {Object} config Configuration options
56328 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
56329 * document.body if omitted)
56331 Roo.ReaderLayout = function(config, renderTo){
56332 var c = config || {size:{}};
56333 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
56334 north: c.north !== false ? Roo.apply({
56338 }, c.north) : false,
56339 west: c.west !== false ? Roo.apply({
56347 margins:{left:5,right:0,bottom:5,top:5},
56348 cmargins:{left:5,right:5,bottom:5,top:5}
56349 }, c.west) : false,
56350 east: c.east !== false ? Roo.apply({
56358 margins:{left:0,right:5,bottom:5,top:5},
56359 cmargins:{left:5,right:5,bottom:5,top:5}
56360 }, c.east) : false,
56361 center: Roo.apply({
56362 tabPosition: 'top',
56366 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
56370 this.el.addClass('x-reader');
56372 this.beginUpdate();
56374 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
56375 south: c.preview !== false ? Roo.apply({
56382 cmargins:{top:5,left:0, right:0, bottom:0}
56383 }, c.preview) : false,
56384 center: Roo.apply({
56390 this.add('center', new Roo.NestedLayoutPanel(inner,
56391 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
56395 this.regions.preview = inner.getRegion('south');
56396 this.regions.listView = inner.getRegion('center');
56399 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
56401 * Ext JS Library 1.1.1
56402 * Copyright(c) 2006-2007, Ext JS, LLC.
56404 * Originally Released Under LGPL - original licence link has changed is not relivant.
56407 * <script type="text/javascript">
56411 * @class Roo.grid.Grid
56412 * @extends Roo.util.Observable
56413 * This class represents the primary interface of a component based grid control.
56414 * <br><br>Usage:<pre><code>
56415 var grid = new Roo.grid.Grid("my-container-id", {
56418 selModel: mySelectionModel,
56419 autoSizeColumns: true,
56420 monitorWindowResize: false,
56421 trackMouseOver: true
56426 * <b>Common Problems:</b><br/>
56427 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
56428 * element will correct this<br/>
56429 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
56430 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
56431 * are unpredictable.<br/>
56432 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
56433 * grid to calculate dimensions/offsets.<br/>
56435 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56436 * The container MUST have some type of size defined for the grid to fill. The container will be
56437 * automatically set to position relative if it isn't already.
56438 * @param {Object} config A config object that sets properties on this grid.
56440 Roo.grid.Grid = function(container, config){
56441 // initialize the container
56442 this.container = Roo.get(container);
56443 this.container.update("");
56444 this.container.setStyle("overflow", "hidden");
56445 this.container.addClass('x-grid-container');
56447 this.id = this.container.id;
56449 Roo.apply(this, config);
56450 // check and correct shorthanded configs
56452 this.dataSource = this.ds;
56456 this.colModel = this.cm;
56460 this.selModel = this.sm;
56464 if (this.selModel) {
56465 this.selModel = Roo.factory(this.selModel, Roo.grid);
56466 this.sm = this.selModel;
56467 this.sm.xmodule = this.xmodule || false;
56469 if (typeof(this.colModel.config) == 'undefined') {
56470 this.colModel = new Roo.grid.ColumnModel(this.colModel);
56471 this.cm = this.colModel;
56472 this.cm.xmodule = this.xmodule || false;
56474 if (this.dataSource) {
56475 this.dataSource= Roo.factory(this.dataSource, Roo.data);
56476 this.ds = this.dataSource;
56477 this.ds.xmodule = this.xmodule || false;
56484 this.container.setWidth(this.width);
56488 this.container.setHeight(this.height);
56495 * The raw click event for the entire grid.
56496 * @param {Roo.EventObject} e
56501 * The raw dblclick event for the entire grid.
56502 * @param {Roo.EventObject} e
56506 * @event contextmenu
56507 * The raw contextmenu event for the entire grid.
56508 * @param {Roo.EventObject} e
56510 "contextmenu" : true,
56513 * The raw mousedown event for the entire grid.
56514 * @param {Roo.EventObject} e
56516 "mousedown" : true,
56519 * The raw mouseup event for the entire grid.
56520 * @param {Roo.EventObject} e
56525 * The raw mouseover event for the entire grid.
56526 * @param {Roo.EventObject} e
56528 "mouseover" : true,
56531 * The raw mouseout event for the entire grid.
56532 * @param {Roo.EventObject} e
56537 * The raw keypress event for the entire grid.
56538 * @param {Roo.EventObject} e
56543 * The raw keydown event for the entire grid.
56544 * @param {Roo.EventObject} e
56552 * Fires when a cell is clicked
56553 * @param {Grid} this
56554 * @param {Number} rowIndex
56555 * @param {Number} columnIndex
56556 * @param {Roo.EventObject} e
56558 "cellclick" : true,
56560 * @event celldblclick
56561 * Fires when a cell is double clicked
56562 * @param {Grid} this
56563 * @param {Number} rowIndex
56564 * @param {Number} columnIndex
56565 * @param {Roo.EventObject} e
56567 "celldblclick" : true,
56570 * Fires when a row is clicked
56571 * @param {Grid} this
56572 * @param {Number} rowIndex
56573 * @param {Roo.EventObject} e
56577 * @event rowdblclick
56578 * Fires when a row is double clicked
56579 * @param {Grid} this
56580 * @param {Number} rowIndex
56581 * @param {Roo.EventObject} e
56583 "rowdblclick" : true,
56585 * @event headerclick
56586 * Fires when a header is clicked
56587 * @param {Grid} this
56588 * @param {Number} columnIndex
56589 * @param {Roo.EventObject} e
56591 "headerclick" : true,
56593 * @event headerdblclick
56594 * Fires when a header cell is double clicked
56595 * @param {Grid} this
56596 * @param {Number} columnIndex
56597 * @param {Roo.EventObject} e
56599 "headerdblclick" : true,
56601 * @event rowcontextmenu
56602 * Fires when a row is right clicked
56603 * @param {Grid} this
56604 * @param {Number} rowIndex
56605 * @param {Roo.EventObject} e
56607 "rowcontextmenu" : true,
56609 * @event cellcontextmenu
56610 * Fires when a cell is right clicked
56611 * @param {Grid} this
56612 * @param {Number} rowIndex
56613 * @param {Number} cellIndex
56614 * @param {Roo.EventObject} e
56616 "cellcontextmenu" : true,
56618 * @event headercontextmenu
56619 * Fires when a header is right clicked
56620 * @param {Grid} this
56621 * @param {Number} columnIndex
56622 * @param {Roo.EventObject} e
56624 "headercontextmenu" : true,
56626 * @event bodyscroll
56627 * Fires when the body element is scrolled
56628 * @param {Number} scrollLeft
56629 * @param {Number} scrollTop
56631 "bodyscroll" : true,
56633 * @event columnresize
56634 * Fires when the user resizes a column
56635 * @param {Number} columnIndex
56636 * @param {Number} newSize
56638 "columnresize" : true,
56640 * @event columnmove
56641 * Fires when the user moves a column
56642 * @param {Number} oldIndex
56643 * @param {Number} newIndex
56645 "columnmove" : true,
56648 * Fires when row(s) start being dragged
56649 * @param {Grid} this
56650 * @param {Roo.GridDD} dd The drag drop object
56651 * @param {event} e The raw browser event
56653 "startdrag" : true,
56656 * Fires when a drag operation is complete
56657 * @param {Grid} this
56658 * @param {Roo.GridDD} dd The drag drop object
56659 * @param {event} e The raw browser event
56664 * Fires when dragged row(s) are dropped on a valid DD target
56665 * @param {Grid} this
56666 * @param {Roo.GridDD} dd The drag drop object
56667 * @param {String} targetId The target drag drop object
56668 * @param {event} e The raw browser event
56673 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56674 * @param {Grid} this
56675 * @param {Roo.GridDD} dd The drag drop object
56676 * @param {String} targetId The target drag drop object
56677 * @param {event} e The raw browser event
56682 * Fires when the dragged row(s) first cross another DD target while being dragged
56683 * @param {Grid} this
56684 * @param {Roo.GridDD} dd The drag drop object
56685 * @param {String} targetId The target drag drop object
56686 * @param {event} e The raw browser event
56688 "dragenter" : true,
56691 * Fires when the dragged row(s) leave another DD target while being dragged
56692 * @param {Grid} this
56693 * @param {Roo.GridDD} dd The drag drop object
56694 * @param {String} targetId The target drag drop object
56695 * @param {event} e The raw browser event
56700 * Fires when a row is rendered, so you can change add a style to it.
56701 * @param {GridView} gridview The grid view
56702 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56708 * Fires when the grid is rendered
56709 * @param {Grid} grid
56714 Roo.grid.Grid.superclass.constructor.call(this);
56716 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
56719 * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
56722 * @cfg {Roo.grid.GridView} view The view that renders the grid (default = Roo.grid.GridView)
56725 * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
56728 * @cfg {Roo.grid.Store} ds The data store for the grid
56731 * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
56734 * @cfg {String} ddGroup - drag drop group.
56737 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
56741 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
56743 minColumnWidth : 25,
56746 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
56747 * <b>on initial render.</b> It is more efficient to explicitly size the columns
56748 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
56750 autoSizeColumns : false,
56753 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
56755 autoSizeHeaders : true,
56758 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
56760 monitorWindowResize : true,
56763 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
56764 * rows measured to get a columns size. Default is 0 (all rows).
56766 maxRowsToMeasure : 0,
56769 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
56771 trackMouseOver : true,
56774 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
56777 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
56781 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
56783 enableDragDrop : false,
56786 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
56788 enableColumnMove : true,
56791 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
56793 enableColumnHide : true,
56796 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
56798 enableRowHeightSync : false,
56801 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
56806 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
56808 autoHeight : false,
56811 * @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.
56813 autoExpandColumn : false,
56816 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
56819 autoExpandMin : 50,
56822 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
56824 autoExpandMax : 1000,
56827 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
56832 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
56836 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
56846 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
56847 * of a fixed width. Default is false.
56850 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
56855 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
56856 * %0 is replaced with the number of selected rows.
56858 ddText : "{0} selected row{1}",
56862 * Called once after all setup has been completed and the grid is ready to be rendered.
56863 * @return {Roo.grid.Grid} this
56865 render : function()
56867 var c = this.container;
56868 // try to detect autoHeight/width mode
56869 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
56870 this.autoHeight = true;
56872 var view = this.getView();
56875 c.on("click", this.onClick, this);
56876 c.on("dblclick", this.onDblClick, this);
56877 c.on("contextmenu", this.onContextMenu, this);
56878 c.on("keydown", this.onKeyDown, this);
56880 c.on("touchstart", this.onTouchStart, this);
56883 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
56885 this.getSelectionModel().init(this);
56890 this.loadMask = new Roo.LoadMask(this.container,
56891 Roo.apply({store:this.dataSource}, this.loadMask));
56895 if (this.toolbar && this.toolbar.xtype) {
56896 this.toolbar.container = this.getView().getHeaderPanel(true);
56897 this.toolbar = new Roo.Toolbar(this.toolbar);
56899 if (this.footer && this.footer.xtype) {
56900 this.footer.dataSource = this.getDataSource();
56901 this.footer.container = this.getView().getFooterPanel(true);
56902 this.footer = Roo.factory(this.footer, Roo);
56904 if (this.dropTarget && this.dropTarget.xtype) {
56905 delete this.dropTarget.xtype;
56906 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
56910 this.rendered = true;
56911 this.fireEvent('render', this);
56916 * Reconfigures the grid to use a different Store and Column Model.
56917 * The View will be bound to the new objects and refreshed.
56918 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
56919 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
56921 reconfigure : function(dataSource, colModel){
56923 this.loadMask.destroy();
56924 this.loadMask = new Roo.LoadMask(this.container,
56925 Roo.apply({store:dataSource}, this.loadMask));
56927 this.view.bind(dataSource, colModel);
56928 this.dataSource = dataSource;
56929 this.colModel = colModel;
56930 this.view.refresh(true);
56934 * Add's a column, default at the end..
56936 * @param {int} position to add (default end)
56937 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
56939 addColumns : function(pos, ar)
56942 for (var i =0;i< ar.length;i++) {
56944 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
56945 this.cm.lookup[cfg.id] = cfg;
56949 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
56950 pos = this.cm.config.length; //this.cm.config.push(cfg);
56952 pos = Math.max(0,pos);
56955 this.cm.config.splice.apply(this.cm.config, ar);
56959 this.view.generateRules(this.cm);
56960 this.view.refresh(true);
56968 onKeyDown : function(e){
56969 this.fireEvent("keydown", e);
56973 * Destroy this grid.
56974 * @param {Boolean} removeEl True to remove the element
56976 destroy : function(removeEl, keepListeners){
56978 this.loadMask.destroy();
56980 var c = this.container;
56981 c.removeAllListeners();
56982 this.view.destroy();
56983 this.colModel.purgeListeners();
56984 if(!keepListeners){
56985 this.purgeListeners();
56988 if(removeEl === true){
56994 processEvent : function(name, e){
56995 // does this fire select???
56996 //Roo.log('grid:processEvent ' + name);
56998 if (name != 'touchstart' ) {
56999 this.fireEvent(name, e);
57002 var t = e.getTarget();
57004 var header = v.findHeaderIndex(t);
57005 if(header !== false){
57006 var ename = name == 'touchstart' ? 'click' : name;
57008 this.fireEvent("header" + ename, this, header, e);
57010 var row = v.findRowIndex(t);
57011 var cell = v.findCellIndex(t);
57012 if (name == 'touchstart') {
57013 // first touch is always a click.
57014 // hopefull this happens after selection is updated.?
57017 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
57018 var cs = this.selModel.getSelectedCell();
57019 if (row == cs[0] && cell == cs[1]){
57023 if (typeof(this.selModel.getSelections) != 'undefined') {
57024 var cs = this.selModel.getSelections();
57025 var ds = this.dataSource;
57026 if (cs.length == 1 && ds.getAt(row) == cs[0]){
57037 this.fireEvent("row" + name, this, row, e);
57038 if(cell !== false){
57039 this.fireEvent("cell" + name, this, row, cell, e);
57046 onClick : function(e){
57047 this.processEvent("click", e);
57050 onTouchStart : function(e){
57051 this.processEvent("touchstart", e);
57055 onContextMenu : function(e, t){
57056 this.processEvent("contextmenu", e);
57060 onDblClick : function(e){
57061 this.processEvent("dblclick", e);
57065 walkCells : function(row, col, step, fn, scope){
57066 var cm = this.colModel, clen = cm.getColumnCount();
57067 var ds = this.dataSource, rlen = ds.getCount(), first = true;
57079 if(fn.call(scope || this, row, col, cm) === true){
57097 if(fn.call(scope || this, row, col, cm) === true){
57109 getSelections : function(){
57110 return this.selModel.getSelections();
57114 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
57115 * but if manual update is required this method will initiate it.
57117 autoSize : function(){
57119 this.view.layout();
57120 if(this.view.adjustForScroll){
57121 this.view.adjustForScroll();
57127 * Returns the grid's underlying element.
57128 * @return {Element} The element
57130 getGridEl : function(){
57131 return this.container;
57134 // private for compatibility, overridden by editor grid
57135 stopEditing : function(){},
57138 * Returns the grid's SelectionModel.
57139 * @return {SelectionModel}
57141 getSelectionModel : function(){
57142 if(!this.selModel){
57143 this.selModel = new Roo.grid.RowSelectionModel();
57145 return this.selModel;
57149 * Returns the grid's DataSource.
57150 * @return {DataSource}
57152 getDataSource : function(){
57153 return this.dataSource;
57157 * Returns the grid's ColumnModel.
57158 * @return {ColumnModel}
57160 getColumnModel : function(){
57161 return this.colModel;
57165 * Returns the grid's GridView object.
57166 * @return {GridView}
57168 getView : function(){
57170 this.view = new Roo.grid.GridView(this.viewConfig);
57171 this.relayEvents(this.view, [
57172 "beforerowremoved", "beforerowsinserted",
57173 "beforerefresh", "rowremoved",
57174 "rowsinserted", "rowupdated" ,"refresh"
57180 * Called to get grid's drag proxy text, by default returns this.ddText.
57181 * Override this to put something different in the dragged text.
57184 getDragDropText : function(){
57185 var count = this.selModel.getCount();
57186 return String.format(this.ddText, count, count == 1 ? '' : 's');
57191 * Ext JS Library 1.1.1
57192 * Copyright(c) 2006-2007, Ext JS, LLC.
57194 * Originally Released Under LGPL - original licence link has changed is not relivant.
57197 * <script type="text/javascript">
57200 * @class Roo.grid.AbstractGridView
57201 * @extends Roo.util.Observable
57203 * Abstract base class for grid Views
57206 Roo.grid.AbstractGridView = function(){
57210 "beforerowremoved" : true,
57211 "beforerowsinserted" : true,
57212 "beforerefresh" : true,
57213 "rowremoved" : true,
57214 "rowsinserted" : true,
57215 "rowupdated" : true,
57218 Roo.grid.AbstractGridView.superclass.constructor.call(this);
57221 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
57222 rowClass : "x-grid-row",
57223 cellClass : "x-grid-cell",
57224 tdClass : "x-grid-td",
57225 hdClass : "x-grid-hd",
57226 splitClass : "x-grid-hd-split",
57228 init: function(grid){
57230 var cid = this.grid.getGridEl().id;
57231 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
57232 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
57233 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
57234 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
57237 getColumnRenderers : function(){
57238 var renderers = [];
57239 var cm = this.grid.colModel;
57240 var colCount = cm.getColumnCount();
57241 for(var i = 0; i < colCount; i++){
57242 renderers[i] = cm.getRenderer(i);
57247 getColumnIds : function(){
57249 var cm = this.grid.colModel;
57250 var colCount = cm.getColumnCount();
57251 for(var i = 0; i < colCount; i++){
57252 ids[i] = cm.getColumnId(i);
57257 getDataIndexes : function(){
57258 if(!this.indexMap){
57259 this.indexMap = this.buildIndexMap();
57261 return this.indexMap.colToData;
57264 getColumnIndexByDataIndex : function(dataIndex){
57265 if(!this.indexMap){
57266 this.indexMap = this.buildIndexMap();
57268 return this.indexMap.dataToCol[dataIndex];
57272 * Set a css style for a column dynamically.
57273 * @param {Number} colIndex The index of the column
57274 * @param {String} name The css property name
57275 * @param {String} value The css value
57277 setCSSStyle : function(colIndex, name, value){
57278 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
57279 Roo.util.CSS.updateRule(selector, name, value);
57282 generateRules : function(cm){
57283 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
57284 Roo.util.CSS.removeStyleSheet(rulesId);
57285 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57286 var cid = cm.getColumnId(i);
57287 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
57288 this.tdSelector, cid, " {\n}\n",
57289 this.hdSelector, cid, " {\n}\n",
57290 this.splitSelector, cid, " {\n}\n");
57292 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
57296 * Ext JS Library 1.1.1
57297 * Copyright(c) 2006-2007, Ext JS, LLC.
57299 * Originally Released Under LGPL - original licence link has changed is not relivant.
57302 * <script type="text/javascript">
57306 // This is a support class used internally by the Grid components
57307 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
57309 this.view = grid.getView();
57310 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
57311 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
57313 this.setHandleElId(Roo.id(hd));
57314 this.setOuterHandleElId(Roo.id(hd2));
57316 this.scroll = false;
57318 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
57320 getDragData : function(e){
57321 var t = Roo.lib.Event.getTarget(e);
57322 var h = this.view.findHeaderCell(t);
57324 return {ddel: h.firstChild, header:h};
57329 onInitDrag : function(e){
57330 this.view.headersDisabled = true;
57331 var clone = this.dragData.ddel.cloneNode(true);
57332 clone.id = Roo.id();
57333 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
57334 this.proxy.update(clone);
57338 afterValidDrop : function(){
57340 setTimeout(function(){
57341 v.headersDisabled = false;
57345 afterInvalidDrop : function(){
57347 setTimeout(function(){
57348 v.headersDisabled = false;
57354 * Ext JS Library 1.1.1
57355 * Copyright(c) 2006-2007, Ext JS, LLC.
57357 * Originally Released Under LGPL - original licence link has changed is not relivant.
57360 * <script type="text/javascript">
57363 // This is a support class used internally by the Grid components
57364 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
57366 this.view = grid.getView();
57367 // split the proxies so they don't interfere with mouse events
57368 this.proxyTop = Roo.DomHelper.append(document.body, {
57369 cls:"col-move-top", html:" "
57371 this.proxyBottom = Roo.DomHelper.append(document.body, {
57372 cls:"col-move-bottom", html:" "
57374 this.proxyTop.hide = this.proxyBottom.hide = function(){
57375 this.setLeftTop(-100,-100);
57376 this.setStyle("visibility", "hidden");
57378 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
57379 // temporarily disabled
57380 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
57381 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
57383 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
57384 proxyOffsets : [-4, -9],
57385 fly: Roo.Element.fly,
57387 getTargetFromEvent : function(e){
57388 var t = Roo.lib.Event.getTarget(e);
57389 var cindex = this.view.findCellIndex(t);
57390 if(cindex !== false){
57391 return this.view.getHeaderCell(cindex);
57396 nextVisible : function(h){
57397 var v = this.view, cm = this.grid.colModel;
57400 if(!cm.isHidden(v.getCellIndex(h))){
57408 prevVisible : function(h){
57409 var v = this.view, cm = this.grid.colModel;
57412 if(!cm.isHidden(v.getCellIndex(h))){
57420 positionIndicator : function(h, n, e){
57421 var x = Roo.lib.Event.getPageX(e);
57422 var r = Roo.lib.Dom.getRegion(n.firstChild);
57423 var px, pt, py = r.top + this.proxyOffsets[1];
57424 if((r.right - x) <= (r.right-r.left)/2){
57425 px = r.right+this.view.borderWidth;
57431 var oldIndex = this.view.getCellIndex(h);
57432 var newIndex = this.view.getCellIndex(n);
57434 if(this.grid.colModel.isFixed(newIndex)){
57438 var locked = this.grid.colModel.isLocked(newIndex);
57443 if(oldIndex < newIndex){
57446 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
57449 px += this.proxyOffsets[0];
57450 this.proxyTop.setLeftTop(px, py);
57451 this.proxyTop.show();
57452 if(!this.bottomOffset){
57453 this.bottomOffset = this.view.mainHd.getHeight();
57455 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
57456 this.proxyBottom.show();
57460 onNodeEnter : function(n, dd, e, data){
57461 if(data.header != n){
57462 this.positionIndicator(data.header, n, e);
57466 onNodeOver : function(n, dd, e, data){
57467 var result = false;
57468 if(data.header != n){
57469 result = this.positionIndicator(data.header, n, e);
57472 this.proxyTop.hide();
57473 this.proxyBottom.hide();
57475 return result ? this.dropAllowed : this.dropNotAllowed;
57478 onNodeOut : function(n, dd, e, data){
57479 this.proxyTop.hide();
57480 this.proxyBottom.hide();
57483 onNodeDrop : function(n, dd, e, data){
57484 var h = data.header;
57486 var cm = this.grid.colModel;
57487 var x = Roo.lib.Event.getPageX(e);
57488 var r = Roo.lib.Dom.getRegion(n.firstChild);
57489 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
57490 var oldIndex = this.view.getCellIndex(h);
57491 var newIndex = this.view.getCellIndex(n);
57492 var locked = cm.isLocked(newIndex);
57496 if(oldIndex < newIndex){
57499 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
57502 cm.setLocked(oldIndex, locked, true);
57503 cm.moveColumn(oldIndex, newIndex);
57504 this.grid.fireEvent("columnmove", oldIndex, newIndex);
57512 * Ext JS Library 1.1.1
57513 * Copyright(c) 2006-2007, Ext JS, LLC.
57515 * Originally Released Under LGPL - original licence link has changed is not relivant.
57518 * <script type="text/javascript">
57522 * @class Roo.grid.GridView
57523 * @extends Roo.util.Observable
57526 * @param {Object} config
57528 Roo.grid.GridView = function(config){
57529 Roo.grid.GridView.superclass.constructor.call(this);
57532 Roo.apply(this, config);
57535 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
57537 unselectable : 'unselectable="on"',
57538 unselectableCls : 'x-unselectable',
57541 rowClass : "x-grid-row",
57543 cellClass : "x-grid-col",
57545 tdClass : "x-grid-td",
57547 hdClass : "x-grid-hd",
57549 splitClass : "x-grid-split",
57551 sortClasses : ["sort-asc", "sort-desc"],
57553 enableMoveAnim : false,
57557 dh : Roo.DomHelper,
57559 fly : Roo.Element.fly,
57561 css : Roo.util.CSS,
57567 scrollIncrement : 22,
57569 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
57571 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
57573 bind : function(ds, cm){
57575 this.ds.un("load", this.onLoad, this);
57576 this.ds.un("datachanged", this.onDataChange, this);
57577 this.ds.un("add", this.onAdd, this);
57578 this.ds.un("remove", this.onRemove, this);
57579 this.ds.un("update", this.onUpdate, this);
57580 this.ds.un("clear", this.onClear, this);
57583 ds.on("load", this.onLoad, this);
57584 ds.on("datachanged", this.onDataChange, this);
57585 ds.on("add", this.onAdd, this);
57586 ds.on("remove", this.onRemove, this);
57587 ds.on("update", this.onUpdate, this);
57588 ds.on("clear", this.onClear, this);
57593 this.cm.un("widthchange", this.onColWidthChange, this);
57594 this.cm.un("headerchange", this.onHeaderChange, this);
57595 this.cm.un("hiddenchange", this.onHiddenChange, this);
57596 this.cm.un("columnmoved", this.onColumnMove, this);
57597 this.cm.un("columnlockchange", this.onColumnLock, this);
57600 this.generateRules(cm);
57601 cm.on("widthchange", this.onColWidthChange, this);
57602 cm.on("headerchange", this.onHeaderChange, this);
57603 cm.on("hiddenchange", this.onHiddenChange, this);
57604 cm.on("columnmoved", this.onColumnMove, this);
57605 cm.on("columnlockchange", this.onColumnLock, this);
57610 init: function(grid){
57611 Roo.grid.GridView.superclass.init.call(this, grid);
57613 this.bind(grid.dataSource, grid.colModel);
57615 grid.on("headerclick", this.handleHeaderClick, this);
57617 if(grid.trackMouseOver){
57618 grid.on("mouseover", this.onRowOver, this);
57619 grid.on("mouseout", this.onRowOut, this);
57621 grid.cancelTextSelection = function(){};
57622 this.gridId = grid.id;
57624 var tpls = this.templates || {};
57627 tpls.master = new Roo.Template(
57628 '<div class="x-grid" hidefocus="true">',
57629 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
57630 '<div class="x-grid-topbar"></div>',
57631 '<div class="x-grid-scroller"><div></div></div>',
57632 '<div class="x-grid-locked">',
57633 '<div class="x-grid-header">{lockedHeader}</div>',
57634 '<div class="x-grid-body">{lockedBody}</div>',
57636 '<div class="x-grid-viewport">',
57637 '<div class="x-grid-header">{header}</div>',
57638 '<div class="x-grid-body">{body}</div>',
57640 '<div class="x-grid-bottombar"></div>',
57642 '<div class="x-grid-resize-proxy"> </div>',
57645 tpls.master.disableformats = true;
57649 tpls.header = new Roo.Template(
57650 '<table border="0" cellspacing="0" cellpadding="0">',
57651 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
57654 tpls.header.disableformats = true;
57656 tpls.header.compile();
57659 tpls.hcell = new Roo.Template(
57660 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
57661 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
57664 tpls.hcell.disableFormats = true;
57666 tpls.hcell.compile();
57669 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
57670 this.unselectableCls + '" ' + this.unselectable +'> </div>');
57671 tpls.hsplit.disableFormats = true;
57673 tpls.hsplit.compile();
57676 tpls.body = new Roo.Template(
57677 '<table border="0" cellspacing="0" cellpadding="0">',
57678 "<tbody>{rows}</tbody>",
57681 tpls.body.disableFormats = true;
57683 tpls.body.compile();
57686 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
57687 tpls.row.disableFormats = true;
57689 tpls.row.compile();
57692 tpls.cell = new Roo.Template(
57693 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
57694 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
57695 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
57698 tpls.cell.disableFormats = true;
57700 tpls.cell.compile();
57702 this.templates = tpls;
57705 // remap these for backwards compat
57706 onColWidthChange : function(){
57707 this.updateColumns.apply(this, arguments);
57709 onHeaderChange : function(){
57710 this.updateHeaders.apply(this, arguments);
57712 onHiddenChange : function(){
57713 this.handleHiddenChange.apply(this, arguments);
57715 onColumnMove : function(){
57716 this.handleColumnMove.apply(this, arguments);
57718 onColumnLock : function(){
57719 this.handleLockChange.apply(this, arguments);
57722 onDataChange : function(){
57724 this.updateHeaderSortState();
57727 onClear : function(){
57731 onUpdate : function(ds, record){
57732 this.refreshRow(record);
57735 refreshRow : function(record){
57736 var ds = this.ds, index;
57737 if(typeof record == 'number'){
57739 record = ds.getAt(index);
57741 index = ds.indexOf(record);
57743 this.insertRows(ds, index, index, true);
57744 this.onRemove(ds, record, index+1, true);
57745 this.syncRowHeights(index, index);
57747 this.fireEvent("rowupdated", this, index, record);
57750 onAdd : function(ds, records, index){
57751 this.insertRows(ds, index, index + (records.length-1));
57754 onRemove : function(ds, record, index, isUpdate){
57755 if(isUpdate !== true){
57756 this.fireEvent("beforerowremoved", this, index, record);
57758 var bt = this.getBodyTable(), lt = this.getLockedTable();
57759 if(bt.rows[index]){
57760 bt.firstChild.removeChild(bt.rows[index]);
57762 if(lt.rows[index]){
57763 lt.firstChild.removeChild(lt.rows[index]);
57765 if(isUpdate !== true){
57766 this.stripeRows(index);
57767 this.syncRowHeights(index, index);
57769 this.fireEvent("rowremoved", this, index, record);
57773 onLoad : function(){
57774 this.scrollToTop();
57778 * Scrolls the grid to the top
57780 scrollToTop : function(){
57782 this.scroller.dom.scrollTop = 0;
57788 * Gets a panel in the header of the grid that can be used for toolbars etc.
57789 * After modifying the contents of this panel a call to grid.autoSize() may be
57790 * required to register any changes in size.
57791 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
57792 * @return Roo.Element
57794 getHeaderPanel : function(doShow){
57796 this.headerPanel.show();
57798 return this.headerPanel;
57802 * Gets a panel in the footer of the grid that can be used for toolbars etc.
57803 * After modifying the contents of this panel a call to grid.autoSize() may be
57804 * required to register any changes in size.
57805 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
57806 * @return Roo.Element
57808 getFooterPanel : function(doShow){
57810 this.footerPanel.show();
57812 return this.footerPanel;
57815 initElements : function(){
57816 var E = Roo.Element;
57817 var el = this.grid.getGridEl().dom.firstChild;
57818 var cs = el.childNodes;
57820 this.el = new E(el);
57822 this.focusEl = new E(el.firstChild);
57823 this.focusEl.swallowEvent("click", true);
57825 this.headerPanel = new E(cs[1]);
57826 this.headerPanel.enableDisplayMode("block");
57828 this.scroller = new E(cs[2]);
57829 this.scrollSizer = new E(this.scroller.dom.firstChild);
57831 this.lockedWrap = new E(cs[3]);
57832 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
57833 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
57835 this.mainWrap = new E(cs[4]);
57836 this.mainHd = new E(this.mainWrap.dom.firstChild);
57837 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
57839 this.footerPanel = new E(cs[5]);
57840 this.footerPanel.enableDisplayMode("block");
57842 this.resizeProxy = new E(cs[6]);
57844 this.headerSelector = String.format(
57845 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
57846 this.lockedHd.id, this.mainHd.id
57849 this.splitterSelector = String.format(
57850 '#{0} div.x-grid-split, #{1} div.x-grid-split',
57851 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
57854 idToCssName : function(s)
57856 return s.replace(/[^a-z0-9]+/ig, '-');
57859 getHeaderCell : function(index){
57860 return Roo.DomQuery.select(this.headerSelector)[index];
57863 getHeaderCellMeasure : function(index){
57864 return this.getHeaderCell(index).firstChild;
57867 getHeaderCellText : function(index){
57868 return this.getHeaderCell(index).firstChild.firstChild;
57871 getLockedTable : function(){
57872 return this.lockedBody.dom.firstChild;
57875 getBodyTable : function(){
57876 return this.mainBody.dom.firstChild;
57879 getLockedRow : function(index){
57880 return this.getLockedTable().rows[index];
57883 getRow : function(index){
57884 return this.getBodyTable().rows[index];
57887 getRowComposite : function(index){
57889 this.rowEl = new Roo.CompositeElementLite();
57891 var els = [], lrow, mrow;
57892 if(lrow = this.getLockedRow(index)){
57895 if(mrow = this.getRow(index)){
57898 this.rowEl.elements = els;
57902 * Gets the 'td' of the cell
57904 * @param {Integer} rowIndex row to select
57905 * @param {Integer} colIndex column to select
57909 getCell : function(rowIndex, colIndex){
57910 var locked = this.cm.getLockedCount();
57912 if(colIndex < locked){
57913 source = this.lockedBody.dom.firstChild;
57915 source = this.mainBody.dom.firstChild;
57916 colIndex -= locked;
57918 return source.rows[rowIndex].childNodes[colIndex];
57921 getCellText : function(rowIndex, colIndex){
57922 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
57925 getCellBox : function(cell){
57926 var b = this.fly(cell).getBox();
57927 if(Roo.isOpera){ // opera fails to report the Y
57928 b.y = cell.offsetTop + this.mainBody.getY();
57933 getCellIndex : function(cell){
57934 var id = String(cell.className).match(this.cellRE);
57936 return parseInt(id[1], 10);
57941 findHeaderIndex : function(n){
57942 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
57943 return r ? this.getCellIndex(r) : false;
57946 findHeaderCell : function(n){
57947 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
57948 return r ? r : false;
57951 findRowIndex : function(n){
57955 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
57956 return r ? r.rowIndex : false;
57959 findCellIndex : function(node){
57960 var stop = this.el.dom;
57961 while(node && node != stop){
57962 if(this.findRE.test(node.className)){
57963 return this.getCellIndex(node);
57965 node = node.parentNode;
57970 getColumnId : function(index){
57971 return this.cm.getColumnId(index);
57974 getSplitters : function()
57976 if(this.splitterSelector){
57977 return Roo.DomQuery.select(this.splitterSelector);
57983 getSplitter : function(index){
57984 return this.getSplitters()[index];
57987 onRowOver : function(e, t){
57989 if((row = this.findRowIndex(t)) !== false){
57990 this.getRowComposite(row).addClass("x-grid-row-over");
57994 onRowOut : function(e, t){
57996 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
57997 this.getRowComposite(row).removeClass("x-grid-row-over");
58001 renderHeaders : function(){
58003 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
58004 var cb = [], lb = [], sb = [], lsb = [], p = {};
58005 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58006 p.cellId = "x-grid-hd-0-" + i;
58007 p.splitId = "x-grid-csplit-0-" + i;
58008 p.id = cm.getColumnId(i);
58009 p.value = cm.getColumnHeader(i) || "";
58010 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
58011 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
58012 if(!cm.isLocked(i)){
58013 cb[cb.length] = ct.apply(p);
58014 sb[sb.length] = st.apply(p);
58016 lb[lb.length] = ct.apply(p);
58017 lsb[lsb.length] = st.apply(p);
58020 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
58021 ht.apply({cells: cb.join(""), splits:sb.join("")})];
58024 updateHeaders : function(){
58025 var html = this.renderHeaders();
58026 this.lockedHd.update(html[0]);
58027 this.mainHd.update(html[1]);
58031 * Focuses the specified row.
58032 * @param {Number} row The row index
58034 focusRow : function(row)
58036 //Roo.log('GridView.focusRow');
58037 var x = this.scroller.dom.scrollLeft;
58038 this.focusCell(row, 0, false);
58039 this.scroller.dom.scrollLeft = x;
58043 * Focuses the specified cell.
58044 * @param {Number} row The row index
58045 * @param {Number} col The column index
58046 * @param {Boolean} hscroll false to disable horizontal scrolling
58048 focusCell : function(row, col, hscroll)
58050 //Roo.log('GridView.focusCell');
58051 var el = this.ensureVisible(row, col, hscroll);
58052 this.focusEl.alignTo(el, "tl-tl");
58054 this.focusEl.focus();
58056 this.focusEl.focus.defer(1, this.focusEl);
58061 * Scrolls the specified cell into view
58062 * @param {Number} row The row index
58063 * @param {Number} col The column index
58064 * @param {Boolean} hscroll false to disable horizontal scrolling
58066 ensureVisible : function(row, col, hscroll)
58068 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
58069 //return null; //disable for testing.
58070 if(typeof row != "number"){
58071 row = row.rowIndex;
58073 if(row < 0 && row >= this.ds.getCount()){
58076 col = (col !== undefined ? col : 0);
58077 var cm = this.grid.colModel;
58078 while(cm.isHidden(col)){
58082 var el = this.getCell(row, col);
58086 var c = this.scroller.dom;
58088 var ctop = parseInt(el.offsetTop, 10);
58089 var cleft = parseInt(el.offsetLeft, 10);
58090 var cbot = ctop + el.offsetHeight;
58091 var cright = cleft + el.offsetWidth;
58093 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
58094 var stop = parseInt(c.scrollTop, 10);
58095 var sleft = parseInt(c.scrollLeft, 10);
58096 var sbot = stop + ch;
58097 var sright = sleft + c.clientWidth;
58099 Roo.log('GridView.ensureVisible:' +
58101 ' c.clientHeight:' + c.clientHeight +
58102 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
58110 c.scrollTop = ctop;
58111 //Roo.log("set scrolltop to ctop DISABLE?");
58112 }else if(cbot > sbot){
58113 //Roo.log("set scrolltop to cbot-ch");
58114 c.scrollTop = cbot-ch;
58117 if(hscroll !== false){
58119 c.scrollLeft = cleft;
58120 }else if(cright > sright){
58121 c.scrollLeft = cright-c.clientWidth;
58128 updateColumns : function(){
58129 this.grid.stopEditing();
58130 var cm = this.grid.colModel, colIds = this.getColumnIds();
58131 //var totalWidth = cm.getTotalWidth();
58133 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58134 //if(cm.isHidden(i)) continue;
58135 var w = cm.getColumnWidth(i);
58136 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
58137 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
58139 this.updateSplitters();
58142 generateRules : function(cm){
58143 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
58144 Roo.util.CSS.removeStyleSheet(rulesId);
58145 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58146 var cid = cm.getColumnId(i);
58148 if(cm.config[i].align){
58149 align = 'text-align:'+cm.config[i].align+';';
58152 if(cm.isHidden(i)){
58153 hidden = 'display:none;';
58155 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
58157 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
58158 this.hdSelector, cid, " {\n", align, width, "}\n",
58159 this.tdSelector, cid, " {\n",hidden,"\n}\n",
58160 this.splitSelector, cid, " {\n", hidden , "\n}\n");
58162 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
58165 updateSplitters : function(){
58166 var cm = this.cm, s = this.getSplitters();
58167 if(s){ // splitters not created yet
58168 var pos = 0, locked = true;
58169 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58170 if(cm.isHidden(i)) {
58173 var w = cm.getColumnWidth(i); // make sure it's a number
58174 if(!cm.isLocked(i) && locked){
58179 s[i].style.left = (pos-this.splitOffset) + "px";
58184 handleHiddenChange : function(colModel, colIndex, hidden){
58186 this.hideColumn(colIndex);
58188 this.unhideColumn(colIndex);
58192 hideColumn : function(colIndex){
58193 var cid = this.getColumnId(colIndex);
58194 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
58195 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
58197 this.updateHeaders();
58199 this.updateSplitters();
58203 unhideColumn : function(colIndex){
58204 var cid = this.getColumnId(colIndex);
58205 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
58206 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
58209 this.updateHeaders();
58211 this.updateSplitters();
58215 insertRows : function(dm, firstRow, lastRow, isUpdate){
58216 if(firstRow == 0 && lastRow == dm.getCount()-1){
58220 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
58222 var s = this.getScrollState();
58223 var markup = this.renderRows(firstRow, lastRow);
58224 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
58225 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
58226 this.restoreScroll(s);
58228 this.fireEvent("rowsinserted", this, firstRow, lastRow);
58229 this.syncRowHeights(firstRow, lastRow);
58230 this.stripeRows(firstRow);
58236 bufferRows : function(markup, target, index){
58237 var before = null, trows = target.rows, tbody = target.tBodies[0];
58238 if(index < trows.length){
58239 before = trows[index];
58241 var b = document.createElement("div");
58242 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
58243 var rows = b.firstChild.rows;
58244 for(var i = 0, len = rows.length; i < len; i++){
58246 tbody.insertBefore(rows[0], before);
58248 tbody.appendChild(rows[0]);
58255 deleteRows : function(dm, firstRow, lastRow){
58256 if(dm.getRowCount()<1){
58257 this.fireEvent("beforerefresh", this);
58258 this.mainBody.update("");
58259 this.lockedBody.update("");
58260 this.fireEvent("refresh", this);
58262 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
58263 var bt = this.getBodyTable();
58264 var tbody = bt.firstChild;
58265 var rows = bt.rows;
58266 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
58267 tbody.removeChild(rows[firstRow]);
58269 this.stripeRows(firstRow);
58270 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
58274 updateRows : function(dataSource, firstRow, lastRow){
58275 var s = this.getScrollState();
58277 this.restoreScroll(s);
58280 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
58284 this.updateHeaderSortState();
58287 getScrollState : function(){
58289 var sb = this.scroller.dom;
58290 return {left: sb.scrollLeft, top: sb.scrollTop};
58293 stripeRows : function(startRow){
58294 if(!this.grid.stripeRows || this.ds.getCount() < 1){
58297 startRow = startRow || 0;
58298 var rows = this.getBodyTable().rows;
58299 var lrows = this.getLockedTable().rows;
58300 var cls = ' x-grid-row-alt ';
58301 for(var i = startRow, len = rows.length; i < len; i++){
58302 var row = rows[i], lrow = lrows[i];
58303 var isAlt = ((i+1) % 2 == 0);
58304 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
58305 if(isAlt == hasAlt){
58309 row.className += " x-grid-row-alt";
58311 row.className = row.className.replace("x-grid-row-alt", "");
58314 lrow.className = row.className;
58319 restoreScroll : function(state){
58320 //Roo.log('GridView.restoreScroll');
58321 var sb = this.scroller.dom;
58322 sb.scrollLeft = state.left;
58323 sb.scrollTop = state.top;
58327 syncScroll : function(){
58328 //Roo.log('GridView.syncScroll');
58329 var sb = this.scroller.dom;
58330 var sh = this.mainHd.dom;
58331 var bs = this.mainBody.dom;
58332 var lv = this.lockedBody.dom;
58333 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
58334 lv.scrollTop = bs.scrollTop = sb.scrollTop;
58337 handleScroll : function(e){
58339 var sb = this.scroller.dom;
58340 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
58344 handleWheel : function(e){
58345 var d = e.getWheelDelta();
58346 this.scroller.dom.scrollTop -= d*22;
58347 // set this here to prevent jumpy scrolling on large tables
58348 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
58352 renderRows : function(startRow, endRow){
58353 // pull in all the crap needed to render rows
58354 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
58355 var colCount = cm.getColumnCount();
58357 if(ds.getCount() < 1){
58361 // build a map for all the columns
58363 for(var i = 0; i < colCount; i++){
58364 var name = cm.getDataIndex(i);
58366 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
58367 renderer : cm.getRenderer(i),
58368 id : cm.getColumnId(i),
58369 locked : cm.isLocked(i),
58370 has_editor : cm.isCellEditable(i)
58374 startRow = startRow || 0;
58375 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
58377 // records to render
58378 var rs = ds.getRange(startRow, endRow);
58380 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
58383 // As much as I hate to duplicate code, this was branched because FireFox really hates
58384 // [].join("") on strings. The performance difference was substantial enough to
58385 // branch this function
58386 doRender : Roo.isGecko ?
58387 function(cs, rs, ds, startRow, colCount, stripe){
58388 var ts = this.templates, ct = ts.cell, rt = ts.row;
58390 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
58392 var hasListener = this.grid.hasListener('rowclass');
58394 for(var j = 0, len = rs.length; j < len; j++){
58395 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
58396 for(var i = 0; i < colCount; i++){
58398 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
58400 p.css = p.attr = "";
58401 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
58402 if(p.value == undefined || p.value === "") {
58403 p.value = " ";
58406 p.css += ' x-grid-editable-cell';
58408 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
58409 p.css += ' x-grid-dirty-cell';
58411 var markup = ct.apply(p);
58419 if(stripe && ((rowIndex+1) % 2 == 0)){
58420 alt.push("x-grid-row-alt")
58423 alt.push( " x-grid-dirty-row");
58426 if(this.getRowClass){
58427 alt.push(this.getRowClass(r, rowIndex));
58433 rowIndex : rowIndex,
58436 this.grid.fireEvent('rowclass', this, rowcfg);
58437 alt.push(rowcfg.rowClass);
58439 rp.alt = alt.join(" ");
58440 lbuf+= rt.apply(rp);
58442 buf+= rt.apply(rp);
58444 return [lbuf, buf];
58446 function(cs, rs, ds, startRow, colCount, stripe){
58447 var ts = this.templates, ct = ts.cell, rt = ts.row;
58449 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
58450 var hasListener = this.grid.hasListener('rowclass');
58453 for(var j = 0, len = rs.length; j < len; j++){
58454 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
58455 for(var i = 0; i < colCount; i++){
58457 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
58459 p.css = p.attr = "";
58460 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
58461 if(p.value == undefined || p.value === "") {
58462 p.value = " ";
58466 p.css += ' x-grid-editable-cell';
58468 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
58469 p.css += ' x-grid-dirty-cell'
58472 var markup = ct.apply(p);
58474 cb[cb.length] = markup;
58476 lcb[lcb.length] = markup;
58480 if(stripe && ((rowIndex+1) % 2 == 0)){
58481 alt.push( "x-grid-row-alt");
58484 alt.push(" x-grid-dirty-row");
58487 if(this.getRowClass){
58488 alt.push( this.getRowClass(r, rowIndex));
58494 rowIndex : rowIndex,
58497 this.grid.fireEvent('rowclass', this, rowcfg);
58498 alt.push(rowcfg.rowClass);
58501 rp.alt = alt.join(" ");
58502 rp.cells = lcb.join("");
58503 lbuf[lbuf.length] = rt.apply(rp);
58504 rp.cells = cb.join("");
58505 buf[buf.length] = rt.apply(rp);
58507 return [lbuf.join(""), buf.join("")];
58510 renderBody : function(){
58511 var markup = this.renderRows();
58512 var bt = this.templates.body;
58513 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
58517 * Refreshes the grid
58518 * @param {Boolean} headersToo
58520 refresh : function(headersToo){
58521 this.fireEvent("beforerefresh", this);
58522 this.grid.stopEditing();
58523 var result = this.renderBody();
58524 this.lockedBody.update(result[0]);
58525 this.mainBody.update(result[1]);
58526 if(headersToo === true){
58527 this.updateHeaders();
58528 this.updateColumns();
58529 this.updateSplitters();
58530 this.updateHeaderSortState();
58532 this.syncRowHeights();
58534 this.fireEvent("refresh", this);
58537 handleColumnMove : function(cm, oldIndex, newIndex){
58538 this.indexMap = null;
58539 var s = this.getScrollState();
58540 this.refresh(true);
58541 this.restoreScroll(s);
58542 this.afterMove(newIndex);
58545 afterMove : function(colIndex){
58546 if(this.enableMoveAnim && Roo.enableFx){
58547 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
58549 // if multisort - fix sortOrder, and reload..
58550 if (this.grid.dataSource.multiSort) {
58551 // the we can call sort again..
58552 var dm = this.grid.dataSource;
58553 var cm = this.grid.colModel;
58555 for(var i = 0; i < cm.config.length; i++ ) {
58557 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
58558 continue; // dont' bother, it's not in sort list or being set.
58561 so.push(cm.config[i].dataIndex);
58564 dm.load(dm.lastOptions);
58571 updateCell : function(dm, rowIndex, dataIndex){
58572 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
58573 if(typeof colIndex == "undefined"){ // not present in grid
58576 var cm = this.grid.colModel;
58577 var cell = this.getCell(rowIndex, colIndex);
58578 var cellText = this.getCellText(rowIndex, colIndex);
58581 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
58582 id : cm.getColumnId(colIndex),
58583 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
58585 var renderer = cm.getRenderer(colIndex);
58586 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
58587 if(typeof val == "undefined" || val === "") {
58590 cellText.innerHTML = val;
58591 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
58592 this.syncRowHeights(rowIndex, rowIndex);
58595 calcColumnWidth : function(colIndex, maxRowsToMeasure){
58597 if(this.grid.autoSizeHeaders){
58598 var h = this.getHeaderCellMeasure(colIndex);
58599 maxWidth = Math.max(maxWidth, h.scrollWidth);
58602 if(this.cm.isLocked(colIndex)){
58603 tb = this.getLockedTable();
58606 tb = this.getBodyTable();
58607 index = colIndex - this.cm.getLockedCount();
58610 var rows = tb.rows;
58611 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
58612 for(var i = 0; i < stopIndex; i++){
58613 var cell = rows[i].childNodes[index].firstChild;
58614 maxWidth = Math.max(maxWidth, cell.scrollWidth);
58617 return maxWidth + /*margin for error in IE*/ 5;
58620 * Autofit a column to its content.
58621 * @param {Number} colIndex
58622 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
58624 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
58625 if(this.cm.isHidden(colIndex)){
58626 return; // can't calc a hidden column
58629 var cid = this.cm.getColumnId(colIndex);
58630 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
58631 if(this.grid.autoSizeHeaders){
58632 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
58635 var newWidth = this.calcColumnWidth(colIndex);
58636 this.cm.setColumnWidth(colIndex,
58637 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
58638 if(!suppressEvent){
58639 this.grid.fireEvent("columnresize", colIndex, newWidth);
58644 * Autofits all columns to their content and then expands to fit any extra space in the grid
58646 autoSizeColumns : function(){
58647 var cm = this.grid.colModel;
58648 var colCount = cm.getColumnCount();
58649 for(var i = 0; i < colCount; i++){
58650 this.autoSizeColumn(i, true, true);
58652 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
58655 this.updateColumns();
58661 * Autofits all columns to the grid's width proportionate with their current size
58662 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
58664 fitColumns : function(reserveScrollSpace){
58665 var cm = this.grid.colModel;
58666 var colCount = cm.getColumnCount();
58670 for (i = 0; i < colCount; i++){
58671 if(!cm.isHidden(i) && !cm.isFixed(i)){
58672 w = cm.getColumnWidth(i);
58678 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
58679 if(reserveScrollSpace){
58682 var frac = (avail - cm.getTotalWidth())/width;
58683 while (cols.length){
58686 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
58688 this.updateColumns();
58692 onRowSelect : function(rowIndex){
58693 var row = this.getRowComposite(rowIndex);
58694 row.addClass("x-grid-row-selected");
58697 onRowDeselect : function(rowIndex){
58698 var row = this.getRowComposite(rowIndex);
58699 row.removeClass("x-grid-row-selected");
58702 onCellSelect : function(row, col){
58703 var cell = this.getCell(row, col);
58705 Roo.fly(cell).addClass("x-grid-cell-selected");
58709 onCellDeselect : function(row, col){
58710 var cell = this.getCell(row, col);
58712 Roo.fly(cell).removeClass("x-grid-cell-selected");
58716 updateHeaderSortState : function(){
58718 // sort state can be single { field: xxx, direction : yyy}
58719 // or { xxx=>ASC , yyy : DESC ..... }
58722 if (!this.ds.multiSort) {
58723 var state = this.ds.getSortState();
58727 mstate[state.field] = state.direction;
58728 // FIXME... - this is not used here.. but might be elsewhere..
58729 this.sortState = state;
58732 mstate = this.ds.sortToggle;
58734 //remove existing sort classes..
58736 var sc = this.sortClasses;
58737 var hds = this.el.select(this.headerSelector).removeClass(sc);
58739 for(var f in mstate) {
58741 var sortColumn = this.cm.findColumnIndex(f);
58743 if(sortColumn != -1){
58744 var sortDir = mstate[f];
58745 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
58754 handleHeaderClick : function(g, index,e){
58756 Roo.log("header click");
58759 // touch events on header are handled by context
58760 this.handleHdCtx(g,index,e);
58765 if(this.headersDisabled){
58768 var dm = g.dataSource, cm = g.colModel;
58769 if(!cm.isSortable(index)){
58774 if (dm.multiSort) {
58775 // update the sortOrder
58777 for(var i = 0; i < cm.config.length; i++ ) {
58779 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
58780 continue; // dont' bother, it's not in sort list or being set.
58783 so.push(cm.config[i].dataIndex);
58789 dm.sort(cm.getDataIndex(index));
58793 destroy : function(){
58795 this.colMenu.removeAll();
58796 Roo.menu.MenuMgr.unregister(this.colMenu);
58797 this.colMenu.getEl().remove();
58798 delete this.colMenu;
58801 this.hmenu.removeAll();
58802 Roo.menu.MenuMgr.unregister(this.hmenu);
58803 this.hmenu.getEl().remove();
58806 if(this.grid.enableColumnMove){
58807 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
58809 for(var dd in dds){
58810 if(!dds[dd].config.isTarget && dds[dd].dragElId){
58811 var elid = dds[dd].dragElId;
58813 Roo.get(elid).remove();
58814 } else if(dds[dd].config.isTarget){
58815 dds[dd].proxyTop.remove();
58816 dds[dd].proxyBottom.remove();
58819 if(Roo.dd.DDM.locationCache[dd]){
58820 delete Roo.dd.DDM.locationCache[dd];
58823 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
58826 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
58827 this.bind(null, null);
58828 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
58831 handleLockChange : function(){
58832 this.refresh(true);
58835 onDenyColumnLock : function(){
58839 onDenyColumnHide : function(){
58843 handleHdMenuClick : function(item){
58844 var index = this.hdCtxIndex;
58845 var cm = this.cm, ds = this.ds;
58848 ds.sort(cm.getDataIndex(index), "ASC");
58851 ds.sort(cm.getDataIndex(index), "DESC");
58854 var lc = cm.getLockedCount();
58855 if(cm.getColumnCount(true) <= lc+1){
58856 this.onDenyColumnLock();
58860 cm.setLocked(index, true, true);
58861 cm.moveColumn(index, lc);
58862 this.grid.fireEvent("columnmove", index, lc);
58864 cm.setLocked(index, true);
58868 var lc = cm.getLockedCount();
58869 if((lc-1) != index){
58870 cm.setLocked(index, false, true);
58871 cm.moveColumn(index, lc-1);
58872 this.grid.fireEvent("columnmove", index, lc-1);
58874 cm.setLocked(index, false);
58877 case 'wider': // used to expand cols on touch..
58879 var cw = cm.getColumnWidth(index);
58880 cw += (item.id == 'wider' ? 1 : -1) * 50;
58881 cw = Math.max(0, cw);
58882 cw = Math.min(cw,4000);
58883 cm.setColumnWidth(index, cw);
58887 index = cm.getIndexById(item.id.substr(4));
58889 if(item.checked && cm.getColumnCount(true) <= 1){
58890 this.onDenyColumnHide();
58893 cm.setHidden(index, item.checked);
58899 beforeColMenuShow : function(){
58900 var cm = this.cm, colCount = cm.getColumnCount();
58901 this.colMenu.removeAll();
58902 for(var i = 0; i < colCount; i++){
58903 this.colMenu.add(new Roo.menu.CheckItem({
58904 id: "col-"+cm.getColumnId(i),
58905 text: cm.getColumnHeader(i),
58906 checked: !cm.isHidden(i),
58912 handleHdCtx : function(g, index, e){
58914 var hd = this.getHeaderCell(index);
58915 this.hdCtxIndex = index;
58916 var ms = this.hmenu.items, cm = this.cm;
58917 ms.get("asc").setDisabled(!cm.isSortable(index));
58918 ms.get("desc").setDisabled(!cm.isSortable(index));
58919 if(this.grid.enableColLock !== false){
58920 ms.get("lock").setDisabled(cm.isLocked(index));
58921 ms.get("unlock").setDisabled(!cm.isLocked(index));
58923 this.hmenu.show(hd, "tl-bl");
58926 handleHdOver : function(e){
58927 var hd = this.findHeaderCell(e.getTarget());
58928 if(hd && !this.headersDisabled){
58929 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
58930 this.fly(hd).addClass("x-grid-hd-over");
58935 handleHdOut : function(e){
58936 var hd = this.findHeaderCell(e.getTarget());
58938 this.fly(hd).removeClass("x-grid-hd-over");
58942 handleSplitDblClick : function(e, t){
58943 var i = this.getCellIndex(t);
58944 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
58945 this.autoSizeColumn(i, true);
58950 render : function(){
58953 var colCount = cm.getColumnCount();
58955 if(this.grid.monitorWindowResize === true){
58956 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
58958 var header = this.renderHeaders();
58959 var body = this.templates.body.apply({rows:""});
58960 var html = this.templates.master.apply({
58963 lockedHeader: header[0],
58967 //this.updateColumns();
58969 this.grid.getGridEl().dom.innerHTML = html;
58971 this.initElements();
58973 // a kludge to fix the random scolling effect in webkit
58974 this.el.on("scroll", function() {
58975 this.el.dom.scrollTop=0; // hopefully not recursive..
58978 this.scroller.on("scroll", this.handleScroll, this);
58979 this.lockedBody.on("mousewheel", this.handleWheel, this);
58980 this.mainBody.on("mousewheel", this.handleWheel, this);
58982 this.mainHd.on("mouseover", this.handleHdOver, this);
58983 this.mainHd.on("mouseout", this.handleHdOut, this);
58984 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
58985 {delegate: "."+this.splitClass});
58987 this.lockedHd.on("mouseover", this.handleHdOver, this);
58988 this.lockedHd.on("mouseout", this.handleHdOut, this);
58989 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
58990 {delegate: "."+this.splitClass});
58992 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
58993 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
58996 this.updateSplitters();
58998 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
58999 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
59000 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
59003 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
59004 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
59006 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
59007 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
59009 if(this.grid.enableColLock !== false){
59010 this.hmenu.add('-',
59011 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
59012 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
59016 this.hmenu.add('-',
59017 {id:"wider", text: this.columnsWiderText},
59018 {id:"narrow", text: this.columnsNarrowText }
59024 if(this.grid.enableColumnHide !== false){
59026 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
59027 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
59028 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
59030 this.hmenu.add('-',
59031 {id:"columns", text: this.columnsText, menu: this.colMenu}
59034 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
59036 this.grid.on("headercontextmenu", this.handleHdCtx, this);
59039 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
59040 this.dd = new Roo.grid.GridDragZone(this.grid, {
59041 ddGroup : this.grid.ddGroup || 'GridDD'
59047 for(var i = 0; i < colCount; i++){
59048 if(cm.isHidden(i)){
59049 this.hideColumn(i);
59051 if(cm.config[i].align){
59052 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
59053 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
59057 this.updateHeaderSortState();
59059 this.beforeInitialResize();
59062 // two part rendering gives faster view to the user
59063 this.renderPhase2.defer(1, this);
59066 renderPhase2 : function(){
59067 // render the rows now
59069 if(this.grid.autoSizeColumns){
59070 this.autoSizeColumns();
59074 beforeInitialResize : function(){
59078 onColumnSplitterMoved : function(i, w){
59079 this.userResized = true;
59080 var cm = this.grid.colModel;
59081 cm.setColumnWidth(i, w, true);
59082 var cid = cm.getColumnId(i);
59083 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
59084 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
59085 this.updateSplitters();
59087 this.grid.fireEvent("columnresize", i, w);
59090 syncRowHeights : function(startIndex, endIndex){
59091 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
59092 startIndex = startIndex || 0;
59093 var mrows = this.getBodyTable().rows;
59094 var lrows = this.getLockedTable().rows;
59095 var len = mrows.length-1;
59096 endIndex = Math.min(endIndex || len, len);
59097 for(var i = startIndex; i <= endIndex; i++){
59098 var m = mrows[i], l = lrows[i];
59099 var h = Math.max(m.offsetHeight, l.offsetHeight);
59100 m.style.height = l.style.height = h + "px";
59105 layout : function(initialRender, is2ndPass)
59108 var auto = g.autoHeight;
59109 var scrollOffset = 16;
59110 var c = g.getGridEl(), cm = this.cm,
59111 expandCol = g.autoExpandColumn,
59113 //c.beginMeasure();
59115 if(!c.dom.offsetWidth){ // display:none?
59117 this.lockedWrap.show();
59118 this.mainWrap.show();
59123 var hasLock = this.cm.isLocked(0);
59125 var tbh = this.headerPanel.getHeight();
59126 var bbh = this.footerPanel.getHeight();
59129 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
59130 var newHeight = ch + c.getBorderWidth("tb");
59132 newHeight = Math.min(g.maxHeight, newHeight);
59134 c.setHeight(newHeight);
59138 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
59141 var s = this.scroller;
59143 var csize = c.getSize(true);
59145 this.el.setSize(csize.width, csize.height);
59147 this.headerPanel.setWidth(csize.width);
59148 this.footerPanel.setWidth(csize.width);
59150 var hdHeight = this.mainHd.getHeight();
59151 var vw = csize.width;
59152 var vh = csize.height - (tbh + bbh);
59156 var bt = this.getBodyTable();
59158 if(cm.getLockedCount() == cm.config.length){
59159 bt = this.getLockedTable();
59162 var ltWidth = hasLock ?
59163 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
59165 var scrollHeight = bt.offsetHeight;
59166 var scrollWidth = ltWidth + bt.offsetWidth;
59167 var vscroll = false, hscroll = false;
59169 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
59171 var lw = this.lockedWrap, mw = this.mainWrap;
59172 var lb = this.lockedBody, mb = this.mainBody;
59174 setTimeout(function(){
59175 var t = s.dom.offsetTop;
59176 var w = s.dom.clientWidth,
59177 h = s.dom.clientHeight;
59180 lw.setSize(ltWidth, h);
59182 mw.setLeftTop(ltWidth, t);
59183 mw.setSize(w-ltWidth, h);
59185 lb.setHeight(h-hdHeight);
59186 mb.setHeight(h-hdHeight);
59188 if(is2ndPass !== true && !gv.userResized && expandCol){
59189 // high speed resize without full column calculation
59191 var ci = cm.getIndexById(expandCol);
59193 ci = cm.findColumnIndex(expandCol);
59195 ci = Math.max(0, ci); // make sure it's got at least the first col.
59196 var expandId = cm.getColumnId(ci);
59197 var tw = cm.getTotalWidth(false);
59198 var currentWidth = cm.getColumnWidth(ci);
59199 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
59200 if(currentWidth != cw){
59201 cm.setColumnWidth(ci, cw, true);
59202 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
59203 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
59204 gv.updateSplitters();
59205 gv.layout(false, true);
59217 onWindowResize : function(){
59218 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
59224 appendFooter : function(parentEl){
59228 sortAscText : "Sort Ascending",
59229 sortDescText : "Sort Descending",
59230 lockText : "Lock Column",
59231 unlockText : "Unlock Column",
59232 columnsText : "Columns",
59234 columnsWiderText : "Wider",
59235 columnsNarrowText : "Thinner"
59239 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
59240 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
59241 this.proxy.el.addClass('x-grid3-col-dd');
59244 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
59245 handleMouseDown : function(e){
59249 callHandleMouseDown : function(e){
59250 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
59255 * Ext JS Library 1.1.1
59256 * Copyright(c) 2006-2007, Ext JS, LLC.
59258 * Originally Released Under LGPL - original licence link has changed is not relivant.
59261 * <script type="text/javascript">
59264 * @extends Roo.dd.DDProxy
59265 * @class Roo.grid.SplitDragZone
59266 * Support for Column Header resizing
59268 * @param {Object} config
59271 // This is a support class used internally by the Grid components
59272 Roo.grid.SplitDragZone = function(grid, hd, hd2){
59274 this.view = grid.getView();
59275 this.proxy = this.view.resizeProxy;
59276 Roo.grid.SplitDragZone.superclass.constructor.call(
59279 "gridSplitters" + this.grid.getGridEl().id, // SGROUP
59281 dragElId : Roo.id(this.proxy.dom),
59286 this.setHandleElId(Roo.id(hd));
59287 if (hd2 !== false) {
59288 this.setOuterHandleElId(Roo.id(hd2));
59291 this.scroll = false;
59293 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
59294 fly: Roo.Element.fly,
59296 b4StartDrag : function(x, y){
59297 this.view.headersDisabled = true;
59298 var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
59299 this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
59301 this.proxy.setHeight(h);
59303 // for old system colWidth really stored the actual width?
59304 // in bootstrap we tried using xs/ms/etc.. to do % sizing?
59305 // which in reality did not work.. - it worked only for fixed sizes
59306 // for resizable we need to use actual sizes.
59307 var w = this.cm.getColumnWidth(this.cellIndex);
59308 if (!this.view.mainWrap) {
59310 w = this.view.getHeaderIndex(this.cellIndex).getWidth();
59315 // this was w-this.grid.minColumnWidth;
59316 // doesnt really make sense? - w = thie curren width or the rendered one?
59317 var minw = Math.max(w-this.grid.minColumnWidth, 0);
59318 this.resetConstraints();
59319 this.setXConstraint(minw, 1000);
59320 this.setYConstraint(0, 0);
59321 this.minX = x - minw;
59322 this.maxX = x + 1000;
59324 if (!this.view.mainWrap) { // this is Bootstrap code..
59325 this.getDragEl().style.display='block';
59328 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
59332 handleMouseDown : function(e){
59333 ev = Roo.EventObject.setEvent(e);
59334 var t = this.fly(ev.getTarget());
59335 if(t.hasClass("x-grid-split")){
59336 this.cellIndex = this.view.getCellIndex(t.dom);
59337 this.split = t.dom;
59338 this.cm = this.grid.colModel;
59339 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
59340 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
59345 endDrag : function(e){
59346 this.view.headersDisabled = false;
59347 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
59348 var diff = endX - this.startPos;
59350 var w = this.cm.getColumnWidth(this.cellIndex);
59351 if (!this.view.mainWrap) {
59354 this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
59357 autoOffset : function(){
59358 this.setDelta(0,0);
59362 * Ext JS Library 1.1.1
59363 * Copyright(c) 2006-2007, Ext JS, LLC.
59365 * Originally Released Under LGPL - original licence link has changed is not relivant.
59368 * <script type="text/javascript">
59372 // This is a support class used internally by the Grid components
59373 Roo.grid.GridDragZone = function(grid, config){
59374 this.view = grid.getView();
59375 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
59376 if(this.view.lockedBody){
59377 this.setHandleElId(Roo.id(this.view.mainBody.dom));
59378 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
59380 this.scroll = false;
59382 this.ddel = document.createElement('div');
59383 this.ddel.className = 'x-grid-dd-wrap';
59386 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
59387 ddGroup : "GridDD",
59389 getDragData : function(e){
59390 var t = Roo.lib.Event.getTarget(e);
59391 var rowIndex = this.view.findRowIndex(t);
59392 var sm = this.grid.selModel;
59394 //Roo.log(rowIndex);
59396 if (sm.getSelectedCell) {
59397 // cell selection..
59398 if (!sm.getSelectedCell()) {
59401 if (rowIndex != sm.getSelectedCell()[0]) {
59406 if (sm.getSelections && sm.getSelections().length < 1) {
59411 // before it used to all dragging of unseleted... - now we dont do that.
59412 if(rowIndex !== false){
59417 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
59419 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
59422 if (e.hasModifier()){
59423 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
59426 Roo.log("getDragData");
59431 rowIndex: rowIndex,
59432 selections: sm.getSelections ? sm.getSelections() : (
59433 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
59440 onInitDrag : function(e){
59441 var data = this.dragData;
59442 this.ddel.innerHTML = this.grid.getDragDropText();
59443 this.proxy.update(this.ddel);
59444 // fire start drag?
59447 afterRepair : function(){
59448 this.dragging = false;
59451 getRepairXY : function(e, data){
59455 onEndDrag : function(data, e){
59459 onValidDrop : function(dd, e, id){
59464 beforeInvalidDrop : function(e, id){
59469 * Ext JS Library 1.1.1
59470 * Copyright(c) 2006-2007, Ext JS, LLC.
59472 * Originally Released Under LGPL - original licence link has changed is not relivant.
59475 * <script type="text/javascript">
59480 * @class Roo.grid.ColumnModel
59481 * @extends Roo.util.Observable
59482 * This is the default implementation of a ColumnModel used by the Grid. It defines
59483 * the columns in the grid.
59486 var colModel = new Roo.grid.ColumnModel([
59487 {header: "Ticker", width: 60, sortable: true, locked: true},
59488 {header: "Company Name", width: 150, sortable: true},
59489 {header: "Market Cap.", width: 100, sortable: true},
59490 {header: "$ Sales", width: 100, sortable: true, renderer: money},
59491 {header: "Employees", width: 100, sortable: true, resizable: false}
59496 * The config options listed for this class are options which may appear in each
59497 * individual column definition.
59498 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
59500 * @param {Object} config An Array of column config objects. See this class's
59501 * config objects for details.
59503 Roo.grid.ColumnModel = function(config){
59505 * The config passed into the constructor
59507 this.config = []; //config;
59510 // if no id, create one
59511 // if the column does not have a dataIndex mapping,
59512 // map it to the order it is in the config
59513 for(var i = 0, len = config.length; i < len; i++){
59514 this.addColumn(config[i]);
59519 * The width of columns which have no width specified (defaults to 100)
59522 this.defaultWidth = 100;
59525 * Default sortable of columns which have no sortable specified (defaults to false)
59528 this.defaultSortable = false;
59532 * @event widthchange
59533 * Fires when the width of a column changes.
59534 * @param {ColumnModel} this
59535 * @param {Number} columnIndex The column index
59536 * @param {Number} newWidth The new width
59538 "widthchange": true,
59540 * @event headerchange
59541 * Fires when the text of a header changes.
59542 * @param {ColumnModel} this
59543 * @param {Number} columnIndex The column index
59544 * @param {Number} newText The new header text
59546 "headerchange": true,
59548 * @event hiddenchange
59549 * Fires when a column is hidden or "unhidden".
59550 * @param {ColumnModel} this
59551 * @param {Number} columnIndex The column index
59552 * @param {Boolean} hidden true if hidden, false otherwise
59554 "hiddenchange": true,
59556 * @event columnmoved
59557 * Fires when a column is moved.
59558 * @param {ColumnModel} this
59559 * @param {Number} oldIndex
59560 * @param {Number} newIndex
59562 "columnmoved" : true,
59564 * @event columlockchange
59565 * Fires when a column's locked state is changed
59566 * @param {ColumnModel} this
59567 * @param {Number} colIndex
59568 * @param {Boolean} locked true if locked
59570 "columnlockchange" : true
59572 Roo.grid.ColumnModel.superclass.constructor.call(this);
59574 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
59576 * @cfg {String} header The header text to display in the Grid view.
59579 * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
59582 * @cfg {String} smHeader Header at Bootsrap Small width
59585 * @cfg {String} mdHeader Header at Bootsrap Medium width
59588 * @cfg {String} lgHeader Header at Bootsrap Large width
59591 * @cfg {String} xlHeader Header at Bootsrap extra Large width
59594 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
59595 * {@link Roo.data.Record} definition from which to draw the column's value. If not
59596 * specified, the column's index is used as an index into the Record's data Array.
59599 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
59600 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
59603 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
59604 * Defaults to the value of the {@link #defaultSortable} property.
59605 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
59608 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
59611 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
59614 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
59617 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
59620 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
59621 * given the cell's data value. See {@link #setRenderer}. If not specified, the
59622 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
59623 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
59626 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
59629 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
59632 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
59635 * @cfg {String} cursor (Optional)
59638 * @cfg {String} tooltip (Optional)
59641 * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
59644 * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
59647 * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
59650 * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
59653 * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
59656 * Returns the id of the column at the specified index.
59657 * @param {Number} index The column index
59658 * @return {String} the id
59660 getColumnId : function(index){
59661 return this.config[index].id;
59665 * Returns the column for a specified id.
59666 * @param {String} id The column id
59667 * @return {Object} the column
59669 getColumnById : function(id){
59670 return this.lookup[id];
59675 * Returns the column Object for a specified dataIndex.
59676 * @param {String} dataIndex The column dataIndex
59677 * @return {Object|Boolean} the column or false if not found
59679 getColumnByDataIndex: function(dataIndex){
59680 var index = this.findColumnIndex(dataIndex);
59681 return index > -1 ? this.config[index] : false;
59685 * Returns the index for a specified column id.
59686 * @param {String} id The column id
59687 * @return {Number} the index, or -1 if not found
59689 getIndexById : function(id){
59690 for(var i = 0, len = this.config.length; i < len; i++){
59691 if(this.config[i].id == id){
59699 * Returns the index for a specified column dataIndex.
59700 * @param {String} dataIndex The column dataIndex
59701 * @return {Number} the index, or -1 if not found
59704 findColumnIndex : function(dataIndex){
59705 for(var i = 0, len = this.config.length; i < len; i++){
59706 if(this.config[i].dataIndex == dataIndex){
59714 moveColumn : function(oldIndex, newIndex){
59715 var c = this.config[oldIndex];
59716 this.config.splice(oldIndex, 1);
59717 this.config.splice(newIndex, 0, c);
59718 this.dataMap = null;
59719 this.fireEvent("columnmoved", this, oldIndex, newIndex);
59722 isLocked : function(colIndex){
59723 return this.config[colIndex].locked === true;
59726 setLocked : function(colIndex, value, suppressEvent){
59727 if(this.isLocked(colIndex) == value){
59730 this.config[colIndex].locked = value;
59731 if(!suppressEvent){
59732 this.fireEvent("columnlockchange", this, colIndex, value);
59736 getTotalLockedWidth : function(){
59737 var totalWidth = 0;
59738 for(var i = 0; i < this.config.length; i++){
59739 if(this.isLocked(i) && !this.isHidden(i)){
59740 this.totalWidth += this.getColumnWidth(i);
59746 getLockedCount : function(){
59747 for(var i = 0, len = this.config.length; i < len; i++){
59748 if(!this.isLocked(i)){
59753 return this.config.length;
59757 * Returns the number of columns.
59760 getColumnCount : function(visibleOnly){
59761 if(visibleOnly === true){
59763 for(var i = 0, len = this.config.length; i < len; i++){
59764 if(!this.isHidden(i)){
59770 return this.config.length;
59774 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
59775 * @param {Function} fn
59776 * @param {Object} scope (optional)
59777 * @return {Array} result
59779 getColumnsBy : function(fn, scope){
59781 for(var i = 0, len = this.config.length; i < len; i++){
59782 var c = this.config[i];
59783 if(fn.call(scope||this, c, i) === true){
59791 * Returns true if the specified column is sortable.
59792 * @param {Number} col The column index
59793 * @return {Boolean}
59795 isSortable : function(col){
59796 if(typeof this.config[col].sortable == "undefined"){
59797 return this.defaultSortable;
59799 return this.config[col].sortable;
59803 * Returns the rendering (formatting) function defined for the column.
59804 * @param {Number} col The column index.
59805 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
59807 getRenderer : function(col){
59808 if(!this.config[col].renderer){
59809 return Roo.grid.ColumnModel.defaultRenderer;
59811 return this.config[col].renderer;
59815 * Sets the rendering (formatting) function for a column.
59816 * @param {Number} col The column index
59817 * @param {Function} fn The function to use to process the cell's raw data
59818 * to return HTML markup for the grid view. The render function is called with
59819 * the following parameters:<ul>
59820 * <li>Data value.</li>
59821 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
59822 * <li>css A CSS style string to apply to the table cell.</li>
59823 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
59824 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
59825 * <li>Row index</li>
59826 * <li>Column index</li>
59827 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
59829 setRenderer : function(col, fn){
59830 this.config[col].renderer = fn;
59834 * Returns the width for the specified column.
59835 * @param {Number} col The column index
59836 * @param (optional) {String} gridSize bootstrap width size.
59839 getColumnWidth : function(col, gridSize)
59841 var cfg = this.config[col];
59843 if (typeof(gridSize) == 'undefined') {
59844 return cfg.width * 1 || this.defaultWidth;
59846 if (gridSize === false) { // if we set it..
59847 return cfg.width || false;
59849 var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
59851 for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
59852 if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
59855 return cfg[ sizes[i] ];
59862 * Sets the width for a column.
59863 * @param {Number} col The column index
59864 * @param {Number} width The new width
59866 setColumnWidth : function(col, width, suppressEvent){
59867 this.config[col].width = width;
59868 this.totalWidth = null;
59869 if(!suppressEvent){
59870 this.fireEvent("widthchange", this, col, width);
59875 * Returns the total width of all columns.
59876 * @param {Boolean} includeHidden True to include hidden column widths
59879 getTotalWidth : function(includeHidden){
59880 if(!this.totalWidth){
59881 this.totalWidth = 0;
59882 for(var i = 0, len = this.config.length; i < len; i++){
59883 if(includeHidden || !this.isHidden(i)){
59884 this.totalWidth += this.getColumnWidth(i);
59888 return this.totalWidth;
59892 * Returns the header for the specified column.
59893 * @param {Number} col The column index
59896 getColumnHeader : function(col){
59897 return this.config[col].header;
59901 * Sets the header for a column.
59902 * @param {Number} col The column index
59903 * @param {String} header The new header
59905 setColumnHeader : function(col, header){
59906 this.config[col].header = header;
59907 this.fireEvent("headerchange", this, col, header);
59911 * Returns the tooltip for the specified column.
59912 * @param {Number} col The column index
59915 getColumnTooltip : function(col){
59916 return this.config[col].tooltip;
59919 * Sets the tooltip for a column.
59920 * @param {Number} col The column index
59921 * @param {String} tooltip The new tooltip
59923 setColumnTooltip : function(col, tooltip){
59924 this.config[col].tooltip = tooltip;
59928 * Returns the dataIndex for the specified column.
59929 * @param {Number} col The column index
59932 getDataIndex : function(col){
59933 return this.config[col].dataIndex;
59937 * Sets the dataIndex for a column.
59938 * @param {Number} col The column index
59939 * @param {Number} dataIndex The new dataIndex
59941 setDataIndex : function(col, dataIndex){
59942 this.config[col].dataIndex = dataIndex;
59948 * Returns true if the cell is editable.
59949 * @param {Number} colIndex The column index
59950 * @param {Number} rowIndex The row index - this is nto actually used..?
59951 * @return {Boolean}
59953 isCellEditable : function(colIndex, rowIndex){
59954 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
59958 * Returns the editor defined for the cell/column.
59959 * return false or null to disable editing.
59960 * @param {Number} colIndex The column index
59961 * @param {Number} rowIndex The row index
59964 getCellEditor : function(colIndex, rowIndex){
59965 return this.config[colIndex].editor;
59969 * Sets if a column is editable.
59970 * @param {Number} col The column index
59971 * @param {Boolean} editable True if the column is editable
59973 setEditable : function(col, editable){
59974 this.config[col].editable = editable;
59979 * Returns true if the column is hidden.
59980 * @param {Number} colIndex The column index
59981 * @return {Boolean}
59983 isHidden : function(colIndex){
59984 return this.config[colIndex].hidden;
59989 * Returns true if the column width cannot be changed
59991 isFixed : function(colIndex){
59992 return this.config[colIndex].fixed;
59996 * Returns true if the column can be resized
59997 * @return {Boolean}
59999 isResizable : function(colIndex){
60000 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
60003 * Sets if a column is hidden.
60004 * @param {Number} colIndex The column index
60005 * @param {Boolean} hidden True if the column is hidden
60007 setHidden : function(colIndex, hidden){
60008 this.config[colIndex].hidden = hidden;
60009 this.totalWidth = null;
60010 this.fireEvent("hiddenchange", this, colIndex, hidden);
60014 * Sets the editor for a column.
60015 * @param {Number} col The column index
60016 * @param {Object} editor The editor object
60018 setEditor : function(col, editor){
60019 this.config[col].editor = editor;
60022 * Add a column (experimental...) - defaults to adding to the end..
60023 * @param {Object} config
60025 addColumn : function(c)
60028 var i = this.config.length;
60029 this.config[i] = c;
60031 if(typeof c.dataIndex == "undefined"){
60034 if(typeof c.renderer == "string"){
60035 c.renderer = Roo.util.Format[c.renderer];
60037 if(typeof c.id == "undefined"){
60040 if(c.editor && c.editor.xtype){
60041 c.editor = Roo.factory(c.editor, Roo.grid);
60043 if(c.editor && c.editor.isFormField){
60044 c.editor = new Roo.grid.GridEditor(c.editor);
60046 this.lookup[c.id] = c;
60051 Roo.grid.ColumnModel.defaultRenderer = function(value)
60053 if(typeof value == "object") {
60056 if(typeof value == "string" && value.length < 1){
60060 return String.format("{0}", value);
60063 // Alias for backwards compatibility
60064 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
60067 * Ext JS Library 1.1.1
60068 * Copyright(c) 2006-2007, Ext JS, LLC.
60070 * Originally Released Under LGPL - original licence link has changed is not relivant.
60073 * <script type="text/javascript">
60077 * @class Roo.grid.AbstractSelectionModel
60078 * @extends Roo.util.Observable
60080 * Abstract base class for grid SelectionModels. It provides the interface that should be
60081 * implemented by descendant classes. This class should not be directly instantiated.
60084 Roo.grid.AbstractSelectionModel = function(){
60085 this.locked = false;
60086 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
60089 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
60090 /** @ignore Called by the grid automatically. Do not call directly. */
60091 init : function(grid){
60097 * Locks the selections.
60100 this.locked = true;
60104 * Unlocks the selections.
60106 unlock : function(){
60107 this.locked = false;
60111 * Returns true if the selections are locked.
60112 * @return {Boolean}
60114 isLocked : function(){
60115 return this.locked;
60119 * Ext JS Library 1.1.1
60120 * Copyright(c) 2006-2007, Ext JS, LLC.
60122 * Originally Released Under LGPL - original licence link has changed is not relivant.
60125 * <script type="text/javascript">
60128 * @extends Roo.grid.AbstractSelectionModel
60129 * @class Roo.grid.RowSelectionModel
60130 * The default SelectionModel used by {@link Roo.grid.Grid}.
60131 * It supports multiple selections and keyboard selection/navigation.
60133 * @param {Object} config
60135 Roo.grid.RowSelectionModel = function(config){
60136 Roo.apply(this, config);
60137 this.selections = new Roo.util.MixedCollection(false, function(o){
60142 this.lastActive = false;
60146 * @event selectionchange
60147 * Fires when the selection changes
60148 * @param {SelectionModel} this
60150 "selectionchange" : true,
60152 * @event afterselectionchange
60153 * Fires after the selection changes (eg. by key press or clicking)
60154 * @param {SelectionModel} this
60156 "afterselectionchange" : true,
60158 * @event beforerowselect
60159 * Fires when a row is selected being selected, return false to cancel.
60160 * @param {SelectionModel} this
60161 * @param {Number} rowIndex The selected index
60162 * @param {Boolean} keepExisting False if other selections will be cleared
60164 "beforerowselect" : true,
60167 * Fires when a row is selected.
60168 * @param {SelectionModel} this
60169 * @param {Number} rowIndex The selected index
60170 * @param {Roo.data.Record} r The record
60172 "rowselect" : true,
60174 * @event rowdeselect
60175 * Fires when a row is deselected.
60176 * @param {SelectionModel} this
60177 * @param {Number} rowIndex The selected index
60179 "rowdeselect" : true
60181 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
60182 this.locked = false;
60185 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
60187 * @cfg {Boolean} singleSelect
60188 * True to allow selection of only one row at a time (defaults to false)
60190 singleSelect : false,
60193 initEvents : function(){
60195 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
60196 this.grid.on("mousedown", this.handleMouseDown, this);
60197 }else{ // allow click to work like normal
60198 this.grid.on("rowclick", this.handleDragableRowClick, this);
60200 // bootstrap does not have a view..
60201 var view = this.grid.view ? this.grid.view : this.grid;
60202 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
60203 "up" : function(e){
60205 this.selectPrevious(e.shiftKey);
60206 }else if(this.last !== false && this.lastActive !== false){
60207 var last = this.last;
60208 this.selectRange(this.last, this.lastActive-1);
60209 view.focusRow(this.lastActive);
60210 if(last !== false){
60214 this.selectFirstRow();
60216 this.fireEvent("afterselectionchange", this);
60218 "down" : function(e){
60220 this.selectNext(e.shiftKey);
60221 }else if(this.last !== false && this.lastActive !== false){
60222 var last = this.last;
60223 this.selectRange(this.last, this.lastActive+1);
60224 view.focusRow(this.lastActive);
60225 if(last !== false){
60229 this.selectFirstRow();
60231 this.fireEvent("afterselectionchange", this);
60237 view.on("refresh", this.onRefresh, this);
60238 view.on("rowupdated", this.onRowUpdated, this);
60239 view.on("rowremoved", this.onRemove, this);
60243 onRefresh : function(){
60244 var ds = this.grid.ds, i, v = this.grid.view;
60245 var s = this.selections;
60246 s.each(function(r){
60247 if((i = ds.indexOfId(r.id)) != -1){
60249 s.add(ds.getAt(i)); // updating the selection relate data
60257 onRemove : function(v, index, r){
60258 this.selections.remove(r);
60262 onRowUpdated : function(v, index, r){
60263 if(this.isSelected(r)){
60264 v.onRowSelect(index);
60270 * @param {Array} records The records to select
60271 * @param {Boolean} keepExisting (optional) True to keep existing selections
60273 selectRecords : function(records, keepExisting){
60275 this.clearSelections();
60277 var ds = this.grid.ds;
60278 for(var i = 0, len = records.length; i < len; i++){
60279 this.selectRow(ds.indexOf(records[i]), true);
60284 * Gets the number of selected rows.
60287 getCount : function(){
60288 return this.selections.length;
60292 * Selects the first row in the grid.
60294 selectFirstRow : function(){
60299 * Select the last row.
60300 * @param {Boolean} keepExisting (optional) True to keep existing selections
60302 selectLastRow : function(keepExisting){
60303 this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
60307 * Selects the row immediately following the last selected row.
60308 * @param {Boolean} keepExisting (optional) True to keep existing selections
60310 selectNext : function(keepExisting){
60311 if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
60312 this.selectRow(this.last+1, keepExisting);
60313 var view = this.grid.view ? this.grid.view : this.grid;
60314 view.focusRow(this.last);
60319 * Selects the row that precedes the last selected row.
60320 * @param {Boolean} keepExisting (optional) True to keep existing selections
60322 selectPrevious : function(keepExisting){
60324 this.selectRow(this.last-1, keepExisting);
60325 var view = this.grid.view ? this.grid.view : this.grid;
60326 view.focusRow(this.last);
60331 * Returns the selected records
60332 * @return {Array} Array of selected records
60334 getSelections : function(){
60335 return [].concat(this.selections.items);
60339 * Returns the first selected record.
60342 getSelected : function(){
60343 return this.selections.itemAt(0);
60348 * Clears all selections.
60350 clearSelections : function(fast){
60355 var ds = this.grid.ds;
60356 var s = this.selections;
60357 s.each(function(r){
60358 this.deselectRow(ds.indexOfId(r.id));
60362 this.selections.clear();
60369 * Selects all rows.
60371 selectAll : function(){
60375 this.selections.clear();
60376 for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
60377 this.selectRow(i, true);
60382 * Returns True if there is a selection.
60383 * @return {Boolean}
60385 hasSelection : function(){
60386 return this.selections.length > 0;
60390 * Returns True if the specified row is selected.
60391 * @param {Number/Record} record The record or index of the record to check
60392 * @return {Boolean}
60394 isSelected : function(index){
60395 var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
60396 return (r && this.selections.key(r.id) ? true : false);
60400 * Returns True if the specified record id is selected.
60401 * @param {String} id The id of record to check
60402 * @return {Boolean}
60404 isIdSelected : function(id){
60405 return (this.selections.key(id) ? true : false);
60409 handleMouseDown : function(e, t)
60411 var view = this.grid.view ? this.grid.view : this.grid;
60413 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
60416 if(e.shiftKey && this.last !== false){
60417 var last = this.last;
60418 this.selectRange(last, rowIndex, e.ctrlKey);
60419 this.last = last; // reset the last
60420 view.focusRow(rowIndex);
60422 var isSelected = this.isSelected(rowIndex);
60423 if(e.button !== 0 && isSelected){
60424 view.focusRow(rowIndex);
60425 }else if(e.ctrlKey && isSelected){
60426 this.deselectRow(rowIndex);
60427 }else if(!isSelected){
60428 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
60429 view.focusRow(rowIndex);
60432 this.fireEvent("afterselectionchange", this);
60435 handleDragableRowClick : function(grid, rowIndex, e)
60437 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
60438 this.selectRow(rowIndex, false);
60439 var view = this.grid.view ? this.grid.view : this.grid;
60440 view.focusRow(rowIndex);
60441 this.fireEvent("afterselectionchange", this);
60446 * Selects multiple rows.
60447 * @param {Array} rows Array of the indexes of the row to select
60448 * @param {Boolean} keepExisting (optional) True to keep existing selections
60450 selectRows : function(rows, keepExisting){
60452 this.clearSelections();
60454 for(var i = 0, len = rows.length; i < len; i++){
60455 this.selectRow(rows[i], true);
60460 * Selects a range of rows. All rows in between startRow and endRow are also selected.
60461 * @param {Number} startRow The index of the first row in the range
60462 * @param {Number} endRow The index of the last row in the range
60463 * @param {Boolean} keepExisting (optional) True to retain existing selections
60465 selectRange : function(startRow, endRow, keepExisting){
60470 this.clearSelections();
60472 if(startRow <= endRow){
60473 for(var i = startRow; i <= endRow; i++){
60474 this.selectRow(i, true);
60477 for(var i = startRow; i >= endRow; i--){
60478 this.selectRow(i, true);
60484 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
60485 * @param {Number} startRow The index of the first row in the range
60486 * @param {Number} endRow The index of the last row in the range
60488 deselectRange : function(startRow, endRow, preventViewNotify){
60492 for(var i = startRow; i <= endRow; i++){
60493 this.deselectRow(i, preventViewNotify);
60499 * @param {Number} row The index of the row to select
60500 * @param {Boolean} keepExisting (optional) True to keep existing selections
60502 selectRow : function(index, keepExisting, preventViewNotify){
60503 if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
60506 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
60507 if(!keepExisting || this.singleSelect){
60508 this.clearSelections();
60510 var r = this.grid.ds.getAt(index);
60511 this.selections.add(r);
60512 this.last = this.lastActive = index;
60513 if(!preventViewNotify){
60514 var view = this.grid.view ? this.grid.view : this.grid;
60515 view.onRowSelect(index);
60517 this.fireEvent("rowselect", this, index, r);
60518 this.fireEvent("selectionchange", this);
60524 * @param {Number} row The index of the row to deselect
60526 deselectRow : function(index, preventViewNotify){
60530 if(this.last == index){
60533 if(this.lastActive == index){
60534 this.lastActive = false;
60536 var r = this.grid.ds.getAt(index);
60537 this.selections.remove(r);
60538 if(!preventViewNotify){
60539 var view = this.grid.view ? this.grid.view : this.grid;
60540 view.onRowDeselect(index);
60542 this.fireEvent("rowdeselect", this, index);
60543 this.fireEvent("selectionchange", this);
60547 restoreLast : function(){
60549 this.last = this._last;
60554 acceptsNav : function(row, col, cm){
60555 return !cm.isHidden(col) && cm.isCellEditable(col, row);
60559 onEditorKey : function(field, e){
60560 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
60565 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
60567 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
60569 }else if(k == e.ENTER && !e.ctrlKey){
60573 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
60575 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
60577 }else if(k == e.ESC){
60581 g.startEditing(newCell[0], newCell[1]);
60586 * Ext JS Library 1.1.1
60587 * Copyright(c) 2006-2007, Ext JS, LLC.
60589 * Originally Released Under LGPL - original licence link has changed is not relivant.
60592 * <script type="text/javascript">
60595 * @class Roo.grid.CellSelectionModel
60596 * @extends Roo.grid.AbstractSelectionModel
60597 * This class provides the basic implementation for cell selection in a grid.
60599 * @param {Object} config The object containing the configuration of this model.
60600 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
60602 Roo.grid.CellSelectionModel = function(config){
60603 Roo.apply(this, config);
60605 this.selection = null;
60609 * @event beforerowselect
60610 * Fires before a cell is selected.
60611 * @param {SelectionModel} this
60612 * @param {Number} rowIndex The selected row index
60613 * @param {Number} colIndex The selected cell index
60615 "beforecellselect" : true,
60617 * @event cellselect
60618 * Fires when a cell is selected.
60619 * @param {SelectionModel} this
60620 * @param {Number} rowIndex The selected row index
60621 * @param {Number} colIndex The selected cell index
60623 "cellselect" : true,
60625 * @event selectionchange
60626 * Fires when the active selection changes.
60627 * @param {SelectionModel} this
60628 * @param {Object} selection null for no selection or an object (o) with two properties
60630 <li>o.record: the record object for the row the selection is in</li>
60631 <li>o.cell: An array of [rowIndex, columnIndex]</li>
60634 "selectionchange" : true,
60637 * Fires when the tab (or enter) was pressed on the last editable cell
60638 * You can use this to trigger add new row.
60639 * @param {SelectionModel} this
60643 * @event beforeeditnext
60644 * Fires before the next editable sell is made active
60645 * You can use this to skip to another cell or fire the tabend
60646 * if you set cell to false
60647 * @param {Object} eventdata object : { cell : [ row, col ] }
60649 "beforeeditnext" : true
60651 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
60654 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
60656 enter_is_tab: false,
60659 initEvents : function(){
60660 this.grid.on("mousedown", this.handleMouseDown, this);
60661 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
60662 var view = this.grid.view;
60663 view.on("refresh", this.onViewChange, this);
60664 view.on("rowupdated", this.onRowUpdated, this);
60665 view.on("beforerowremoved", this.clearSelections, this);
60666 view.on("beforerowsinserted", this.clearSelections, this);
60667 if(this.grid.isEditor){
60668 this.grid.on("beforeedit", this.beforeEdit, this);
60673 beforeEdit : function(e){
60674 this.select(e.row, e.column, false, true, e.record);
60678 onRowUpdated : function(v, index, r){
60679 if(this.selection && this.selection.record == r){
60680 v.onCellSelect(index, this.selection.cell[1]);
60685 onViewChange : function(){
60686 this.clearSelections(true);
60690 * Returns the currently selected cell,.
60691 * @return {Array} The selected cell (row, column) or null if none selected.
60693 getSelectedCell : function(){
60694 return this.selection ? this.selection.cell : null;
60698 * Clears all selections.
60699 * @param {Boolean} true to prevent the gridview from being notified about the change.
60701 clearSelections : function(preventNotify){
60702 var s = this.selection;
60704 if(preventNotify !== true){
60705 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
60707 this.selection = null;
60708 this.fireEvent("selectionchange", this, null);
60713 * Returns true if there is a selection.
60714 * @return {Boolean}
60716 hasSelection : function(){
60717 return this.selection ? true : false;
60721 handleMouseDown : function(e, t){
60722 var v = this.grid.getView();
60723 if(this.isLocked()){
60726 var row = v.findRowIndex(t);
60727 var cell = v.findCellIndex(t);
60728 if(row !== false && cell !== false){
60729 this.select(row, cell);
60735 * @param {Number} rowIndex
60736 * @param {Number} collIndex
60738 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
60739 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
60740 this.clearSelections();
60741 r = r || this.grid.dataSource.getAt(rowIndex);
60744 cell : [rowIndex, colIndex]
60746 if(!preventViewNotify){
60747 var v = this.grid.getView();
60748 v.onCellSelect(rowIndex, colIndex);
60749 if(preventFocus !== true){
60750 v.focusCell(rowIndex, colIndex);
60753 this.fireEvent("cellselect", this, rowIndex, colIndex);
60754 this.fireEvent("selectionchange", this, this.selection);
60759 isSelectable : function(rowIndex, colIndex, cm){
60760 return !cm.isHidden(colIndex);
60764 handleKeyDown : function(e){
60765 //Roo.log('Cell Sel Model handleKeyDown');
60766 if(!e.isNavKeyPress()){
60769 var g = this.grid, s = this.selection;
60772 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
60774 this.select(cell[0], cell[1]);
60779 var walk = function(row, col, step){
60780 return g.walkCells(row, col, step, sm.isSelectable, sm);
60782 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
60789 // handled by onEditorKey
60790 if (g.isEditor && g.editing) {
60794 newCell = walk(r, c-1, -1);
60796 newCell = walk(r, c+1, 1);
60801 newCell = walk(r+1, c, 1);
60805 newCell = walk(r-1, c, -1);
60809 newCell = walk(r, c+1, 1);
60813 newCell = walk(r, c-1, -1);
60818 if(g.isEditor && !g.editing){
60819 g.startEditing(r, c);
60828 this.select(newCell[0], newCell[1]);
60834 acceptsNav : function(row, col, cm){
60835 return !cm.isHidden(col) && cm.isCellEditable(col, row);
60839 * @param {Number} field (not used) - as it's normally used as a listener
60840 * @param {Number} e - event - fake it by using
60842 * var e = Roo.EventObjectImpl.prototype;
60843 * e.keyCode = e.TAB
60847 onEditorKey : function(field, e){
60849 var k = e.getKey(),
60852 ed = g.activeEditor,
60854 ///Roo.log('onEditorKey' + k);
60857 if (this.enter_is_tab && k == e.ENTER) {
60863 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
60865 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
60871 } else if(k == e.ENTER && !e.ctrlKey){
60874 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
60876 } else if(k == e.ESC){
60881 var ecall = { cell : newCell, forward : forward };
60882 this.fireEvent('beforeeditnext', ecall );
60883 newCell = ecall.cell;
60884 forward = ecall.forward;
60888 //Roo.log('next cell after edit');
60889 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
60890 } else if (forward) {
60891 // tabbed past last
60892 this.fireEvent.defer(100, this, ['tabend',this]);
60897 * Ext JS Library 1.1.1
60898 * Copyright(c) 2006-2007, Ext JS, LLC.
60900 * Originally Released Under LGPL - original licence link has changed is not relivant.
60903 * <script type="text/javascript">
60907 * @class Roo.grid.EditorGrid
60908 * @extends Roo.grid.Grid
60909 * Class for creating and editable grid.
60910 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60911 * The container MUST have some type of size defined for the grid to fill. The container will be
60912 * automatically set to position relative if it isn't already.
60913 * @param {Object} dataSource The data model to bind to
60914 * @param {Object} colModel The column model with info about this grid's columns
60916 Roo.grid.EditorGrid = function(container, config){
60917 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
60918 this.getGridEl().addClass("xedit-grid");
60920 if(!this.selModel){
60921 this.selModel = new Roo.grid.CellSelectionModel();
60924 this.activeEditor = null;
60928 * @event beforeedit
60929 * Fires before cell editing is triggered. The edit event object has the following properties <br />
60930 * <ul style="padding:5px;padding-left:16px;">
60931 * <li>grid - This grid</li>
60932 * <li>record - The record being edited</li>
60933 * <li>field - The field name being edited</li>
60934 * <li>value - The value for the field being edited.</li>
60935 * <li>row - The grid row index</li>
60936 * <li>column - The grid column index</li>
60937 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
60939 * @param {Object} e An edit event (see above for description)
60941 "beforeedit" : true,
60944 * Fires after a cell is edited. <br />
60945 * <ul style="padding:5px;padding-left:16px;">
60946 * <li>grid - This grid</li>
60947 * <li>record - The record being edited</li>
60948 * <li>field - The field name being edited</li>
60949 * <li>value - The value being set</li>
60950 * <li>originalValue - The original value for the field, before the edit.</li>
60951 * <li>row - The grid row index</li>
60952 * <li>column - The grid column index</li>
60954 * @param {Object} e An edit event (see above for description)
60956 "afteredit" : true,
60958 * @event validateedit
60959 * Fires after a cell is edited, but before the value is set in the record.
60960 * You can use this to modify the value being set in the field, Return false
60961 * to cancel the change. The edit event object has the following properties <br />
60962 * <ul style="padding:5px;padding-left:16px;">
60963 * <li>editor - This editor</li>
60964 * <li>grid - This grid</li>
60965 * <li>record - The record being edited</li>
60966 * <li>field - The field name being edited</li>
60967 * <li>value - The value being set</li>
60968 * <li>originalValue - The original value for the field, before the edit.</li>
60969 * <li>row - The grid row index</li>
60970 * <li>column - The grid column index</li>
60971 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
60973 * @param {Object} e An edit event (see above for description)
60975 "validateedit" : true
60977 this.on("bodyscroll", this.stopEditing, this);
60978 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
60981 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
60983 * @cfg {Number} clicksToEdit
60984 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
60991 trackMouseOver: false, // causes very odd FF errors
60993 onCellDblClick : function(g, row, col){
60994 this.startEditing(row, col);
60997 onEditComplete : function(ed, value, startValue){
60998 this.editing = false;
60999 this.activeEditor = null;
61000 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
61002 var field = this.colModel.getDataIndex(ed.col);
61007 originalValue: startValue,
61014 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
61017 if(String(value) !== String(startValue)){
61019 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
61020 r.set(field, e.value);
61021 // if we are dealing with a combo box..
61022 // then we also set the 'name' colum to be the displayField
61023 if (ed.field.displayField && ed.field.name) {
61024 r.set(ed.field.name, ed.field.el.dom.value);
61027 delete e.cancel; //?? why!!!
61028 this.fireEvent("afteredit", e);
61031 this.fireEvent("afteredit", e); // always fire it!
61033 this.view.focusCell(ed.row, ed.col);
61037 * Starts editing the specified for the specified row/column
61038 * @param {Number} rowIndex
61039 * @param {Number} colIndex
61041 startEditing : function(row, col){
61042 this.stopEditing();
61043 if(this.colModel.isCellEditable(col, row)){
61044 this.view.ensureVisible(row, col, true);
61046 var r = this.dataSource.getAt(row);
61047 var field = this.colModel.getDataIndex(col);
61048 var cell = Roo.get(this.view.getCell(row,col));
61053 value: r.data[field],
61058 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
61059 this.editing = true;
61060 var ed = this.colModel.getCellEditor(col, row);
61066 ed.render(ed.parentEl || document.body);
61072 (function(){ // complex but required for focus issues in safari, ie and opera
61076 ed.on("complete", this.onEditComplete, this, {single: true});
61077 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
61078 this.activeEditor = ed;
61079 var v = r.data[field];
61080 ed.startEdit(this.view.getCell(row, col), v);
61081 // combo's with 'displayField and name set
61082 if (ed.field.displayField && ed.field.name) {
61083 ed.field.el.dom.value = r.data[ed.field.name];
61087 }).defer(50, this);
61093 * Stops any active editing
61095 stopEditing : function(){
61096 if(this.activeEditor){
61097 this.activeEditor.completeEdit();
61099 this.activeEditor = null;
61103 * Called to get grid's drag proxy text, by default returns this.ddText.
61106 getDragDropText : function(){
61107 var count = this.selModel.getSelectedCell() ? 1 : 0;
61108 return String.format(this.ddText, count, count == 1 ? '' : 's');
61113 * Ext JS Library 1.1.1
61114 * Copyright(c) 2006-2007, Ext JS, LLC.
61116 * Originally Released Under LGPL - original licence link has changed is not relivant.
61119 * <script type="text/javascript">
61122 // private - not really -- you end up using it !
61123 // This is a support class used internally by the Grid components
61126 * @class Roo.grid.GridEditor
61127 * @extends Roo.Editor
61128 * Class for creating and editable grid elements.
61129 * @param {Object} config any settings (must include field)
61131 Roo.grid.GridEditor = function(field, config){
61132 if (!config && field.field) {
61134 field = Roo.factory(config.field, Roo.form);
61136 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
61137 field.monitorTab = false;
61140 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
61143 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
61146 alignment: "tl-tl",
61149 cls: "x-small-editor x-grid-editor",
61154 * Ext JS Library 1.1.1
61155 * Copyright(c) 2006-2007, Ext JS, LLC.
61157 * Originally Released Under LGPL - original licence link has changed is not relivant.
61160 * <script type="text/javascript">
61165 Roo.grid.PropertyRecord = Roo.data.Record.create([
61166 {name:'name',type:'string'}, 'value'
61170 Roo.grid.PropertyStore = function(grid, source){
61172 this.store = new Roo.data.Store({
61173 recordType : Roo.grid.PropertyRecord
61175 this.store.on('update', this.onUpdate, this);
61177 this.setSource(source);
61179 Roo.grid.PropertyStore.superclass.constructor.call(this);
61184 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
61185 setSource : function(o){
61187 this.store.removeAll();
61190 if(this.isEditableValue(o[k])){
61191 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
61194 this.store.loadRecords({records: data}, {}, true);
61197 onUpdate : function(ds, record, type){
61198 if(type == Roo.data.Record.EDIT){
61199 var v = record.data['value'];
61200 var oldValue = record.modified['value'];
61201 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
61202 this.source[record.id] = v;
61204 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
61211 getProperty : function(row){
61212 return this.store.getAt(row);
61215 isEditableValue: function(val){
61216 if(val && val instanceof Date){
61218 }else if(typeof val == 'object' || typeof val == 'function'){
61224 setValue : function(prop, value){
61225 this.source[prop] = value;
61226 this.store.getById(prop).set('value', value);
61229 getSource : function(){
61230 return this.source;
61234 Roo.grid.PropertyColumnModel = function(grid, store){
61237 g.PropertyColumnModel.superclass.constructor.call(this, [
61238 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
61239 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
61241 this.store = store;
61242 this.bselect = Roo.DomHelper.append(document.body, {
61243 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
61244 {tag: 'option', value: 'true', html: 'true'},
61245 {tag: 'option', value: 'false', html: 'false'}
61248 Roo.id(this.bselect);
61251 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
61252 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
61253 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
61254 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
61255 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
61257 this.renderCellDelegate = this.renderCell.createDelegate(this);
61258 this.renderPropDelegate = this.renderProp.createDelegate(this);
61261 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
61265 valueText : 'Value',
61267 dateFormat : 'm/j/Y',
61270 renderDate : function(dateVal){
61271 return dateVal.dateFormat(this.dateFormat);
61274 renderBool : function(bVal){
61275 return bVal ? 'true' : 'false';
61278 isCellEditable : function(colIndex, rowIndex){
61279 return colIndex == 1;
61282 getRenderer : function(col){
61284 this.renderCellDelegate : this.renderPropDelegate;
61287 renderProp : function(v){
61288 return this.getPropertyName(v);
61291 renderCell : function(val){
61293 if(val instanceof Date){
61294 rv = this.renderDate(val);
61295 }else if(typeof val == 'boolean'){
61296 rv = this.renderBool(val);
61298 return Roo.util.Format.htmlEncode(rv);
61301 getPropertyName : function(name){
61302 var pn = this.grid.propertyNames;
61303 return pn && pn[name] ? pn[name] : name;
61306 getCellEditor : function(colIndex, rowIndex){
61307 var p = this.store.getProperty(rowIndex);
61308 var n = p.data['name'], val = p.data['value'];
61310 if(typeof(this.grid.customEditors[n]) == 'string'){
61311 return this.editors[this.grid.customEditors[n]];
61313 if(typeof(this.grid.customEditors[n]) != 'undefined'){
61314 return this.grid.customEditors[n];
61316 if(val instanceof Date){
61317 return this.editors['date'];
61318 }else if(typeof val == 'number'){
61319 return this.editors['number'];
61320 }else if(typeof val == 'boolean'){
61321 return this.editors['boolean'];
61323 return this.editors['string'];
61329 * @class Roo.grid.PropertyGrid
61330 * @extends Roo.grid.EditorGrid
61331 * This class represents the interface of a component based property grid control.
61332 * <br><br>Usage:<pre><code>
61333 var grid = new Roo.grid.PropertyGrid("my-container-id", {
61341 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
61342 * The container MUST have some type of size defined for the grid to fill. The container will be
61343 * automatically set to position relative if it isn't already.
61344 * @param {Object} config A config object that sets properties on this grid.
61346 Roo.grid.PropertyGrid = function(container, config){
61347 config = config || {};
61348 var store = new Roo.grid.PropertyStore(this);
61349 this.store = store;
61350 var cm = new Roo.grid.PropertyColumnModel(this, store);
61351 store.store.sort('name', 'ASC');
61352 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
61355 enableColLock:false,
61356 enableColumnMove:false,
61358 trackMouseOver: false,
61361 this.getGridEl().addClass('x-props-grid');
61362 this.lastEditRow = null;
61363 this.on('columnresize', this.onColumnResize, this);
61366 * @event beforepropertychange
61367 * Fires before a property changes (return false to stop?)
61368 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
61369 * @param {String} id Record Id
61370 * @param {String} newval New Value
61371 * @param {String} oldval Old Value
61373 "beforepropertychange": true,
61375 * @event propertychange
61376 * Fires after a property changes
61377 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
61378 * @param {String} id Record Id
61379 * @param {String} newval New Value
61380 * @param {String} oldval Old Value
61382 "propertychange": true
61384 this.customEditors = this.customEditors || {};
61386 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
61389 * @cfg {Object} customEditors map of colnames=> custom editors.
61390 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
61391 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
61392 * false disables editing of the field.
61396 * @cfg {Object} propertyNames map of property Names to their displayed value
61399 render : function(){
61400 Roo.grid.PropertyGrid.superclass.render.call(this);
61401 this.autoSize.defer(100, this);
61404 autoSize : function(){
61405 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
61407 this.view.fitColumns();
61411 onColumnResize : function(){
61412 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
61416 * Sets the data for the Grid
61417 * accepts a Key => Value object of all the elements avaiable.
61418 * @param {Object} data to appear in grid.
61420 setSource : function(source){
61421 this.store.setSource(source);
61425 * Gets all the data from the grid.
61426 * @return {Object} data data stored in grid
61428 getSource : function(){
61429 return this.store.getSource();
61438 * @class Roo.grid.Calendar
61439 * @extends Roo.grid.Grid
61440 * This class extends the Grid to provide a calendar widget
61441 * <br><br>Usage:<pre><code>
61442 var grid = new Roo.grid.Calendar("my-container-id", {
61445 selModel: mySelectionModel,
61446 autoSizeColumns: true,
61447 monitorWindowResize: false,
61448 trackMouseOver: true
61449 eventstore : real data store..
61455 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
61456 * The container MUST have some type of size defined for the grid to fill. The container will be
61457 * automatically set to position relative if it isn't already.
61458 * @param {Object} config A config object that sets properties on this grid.
61460 Roo.grid.Calendar = function(container, config){
61461 // initialize the container
61462 this.container = Roo.get(container);
61463 this.container.update("");
61464 this.container.setStyle("overflow", "hidden");
61465 this.container.addClass('x-grid-container');
61467 this.id = this.container.id;
61469 Roo.apply(this, config);
61470 // check and correct shorthanded configs
61474 for (var r = 0;r < 6;r++) {
61477 for (var c =0;c < 7;c++) {
61481 if (this.eventStore) {
61482 this.eventStore= Roo.factory(this.eventStore, Roo.data);
61483 this.eventStore.on('load',this.onLoad, this);
61484 this.eventStore.on('beforeload',this.clearEvents, this);
61488 this.dataSource = new Roo.data.Store({
61489 proxy: new Roo.data.MemoryProxy(rows),
61490 reader: new Roo.data.ArrayReader({}, [
61491 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
61494 this.dataSource.load();
61495 this.ds = this.dataSource;
61496 this.ds.xmodule = this.xmodule || false;
61499 var cellRender = function(v,x,r)
61501 return String.format(
61502 '<div class="fc-day fc-widget-content"><div>' +
61503 '<div class="fc-event-container"></div>' +
61504 '<div class="fc-day-number">{0}</div>'+
61506 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
61507 '</div></div>', v);
61512 this.colModel = new Roo.grid.ColumnModel( [
61514 xtype: 'ColumnModel',
61516 dataIndex : 'weekday0',
61518 renderer : cellRender
61521 xtype: 'ColumnModel',
61523 dataIndex : 'weekday1',
61525 renderer : cellRender
61528 xtype: 'ColumnModel',
61530 dataIndex : 'weekday2',
61531 header : 'Tuesday',
61532 renderer : cellRender
61535 xtype: 'ColumnModel',
61537 dataIndex : 'weekday3',
61538 header : 'Wednesday',
61539 renderer : cellRender
61542 xtype: 'ColumnModel',
61544 dataIndex : 'weekday4',
61545 header : 'Thursday',
61546 renderer : cellRender
61549 xtype: 'ColumnModel',
61551 dataIndex : 'weekday5',
61553 renderer : cellRender
61556 xtype: 'ColumnModel',
61558 dataIndex : 'weekday6',
61559 header : 'Saturday',
61560 renderer : cellRender
61563 this.cm = this.colModel;
61564 this.cm.xmodule = this.xmodule || false;
61568 //this.selModel = new Roo.grid.CellSelectionModel();
61569 //this.sm = this.selModel;
61570 //this.selModel.init(this);
61574 this.container.setWidth(this.width);
61578 this.container.setHeight(this.height);
61585 * The raw click event for the entire grid.
61586 * @param {Roo.EventObject} e
61591 * The raw dblclick event for the entire grid.
61592 * @param {Roo.EventObject} e
61596 * @event contextmenu
61597 * The raw contextmenu event for the entire grid.
61598 * @param {Roo.EventObject} e
61600 "contextmenu" : true,
61603 * The raw mousedown event for the entire grid.
61604 * @param {Roo.EventObject} e
61606 "mousedown" : true,
61609 * The raw mouseup event for the entire grid.
61610 * @param {Roo.EventObject} e
61615 * The raw mouseover event for the entire grid.
61616 * @param {Roo.EventObject} e
61618 "mouseover" : true,
61621 * The raw mouseout event for the entire grid.
61622 * @param {Roo.EventObject} e
61627 * The raw keypress event for the entire grid.
61628 * @param {Roo.EventObject} e
61633 * The raw keydown event for the entire grid.
61634 * @param {Roo.EventObject} e
61642 * Fires when a cell is clicked
61643 * @param {Grid} this
61644 * @param {Number} rowIndex
61645 * @param {Number} columnIndex
61646 * @param {Roo.EventObject} e
61648 "cellclick" : true,
61650 * @event celldblclick
61651 * Fires when a cell is double clicked
61652 * @param {Grid} this
61653 * @param {Number} rowIndex
61654 * @param {Number} columnIndex
61655 * @param {Roo.EventObject} e
61657 "celldblclick" : true,
61660 * Fires when a row is clicked
61661 * @param {Grid} this
61662 * @param {Number} rowIndex
61663 * @param {Roo.EventObject} e
61667 * @event rowdblclick
61668 * Fires when a row is double clicked
61669 * @param {Grid} this
61670 * @param {Number} rowIndex
61671 * @param {Roo.EventObject} e
61673 "rowdblclick" : true,
61675 * @event headerclick
61676 * Fires when a header is clicked
61677 * @param {Grid} this
61678 * @param {Number} columnIndex
61679 * @param {Roo.EventObject} e
61681 "headerclick" : true,
61683 * @event headerdblclick
61684 * Fires when a header cell is double clicked
61685 * @param {Grid} this
61686 * @param {Number} columnIndex
61687 * @param {Roo.EventObject} e
61689 "headerdblclick" : true,
61691 * @event rowcontextmenu
61692 * Fires when a row is right clicked
61693 * @param {Grid} this
61694 * @param {Number} rowIndex
61695 * @param {Roo.EventObject} e
61697 "rowcontextmenu" : true,
61699 * @event cellcontextmenu
61700 * Fires when a cell is right clicked
61701 * @param {Grid} this
61702 * @param {Number} rowIndex
61703 * @param {Number} cellIndex
61704 * @param {Roo.EventObject} e
61706 "cellcontextmenu" : true,
61708 * @event headercontextmenu
61709 * Fires when a header is right clicked
61710 * @param {Grid} this
61711 * @param {Number} columnIndex
61712 * @param {Roo.EventObject} e
61714 "headercontextmenu" : true,
61716 * @event bodyscroll
61717 * Fires when the body element is scrolled
61718 * @param {Number} scrollLeft
61719 * @param {Number} scrollTop
61721 "bodyscroll" : true,
61723 * @event columnresize
61724 * Fires when the user resizes a column
61725 * @param {Number} columnIndex
61726 * @param {Number} newSize
61728 "columnresize" : true,
61730 * @event columnmove
61731 * Fires when the user moves a column
61732 * @param {Number} oldIndex
61733 * @param {Number} newIndex
61735 "columnmove" : true,
61738 * Fires when row(s) start being dragged
61739 * @param {Grid} this
61740 * @param {Roo.GridDD} dd The drag drop object
61741 * @param {event} e The raw browser event
61743 "startdrag" : true,
61746 * Fires when a drag operation is complete
61747 * @param {Grid} this
61748 * @param {Roo.GridDD} dd The drag drop object
61749 * @param {event} e The raw browser event
61754 * Fires when dragged row(s) are dropped on a valid DD target
61755 * @param {Grid} this
61756 * @param {Roo.GridDD} dd The drag drop object
61757 * @param {String} targetId The target drag drop object
61758 * @param {event} e The raw browser event
61763 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
61764 * @param {Grid} this
61765 * @param {Roo.GridDD} dd The drag drop object
61766 * @param {String} targetId The target drag drop object
61767 * @param {event} e The raw browser event
61772 * Fires when the dragged row(s) first cross another DD target while being dragged
61773 * @param {Grid} this
61774 * @param {Roo.GridDD} dd The drag drop object
61775 * @param {String} targetId The target drag drop object
61776 * @param {event} e The raw browser event
61778 "dragenter" : true,
61781 * Fires when the dragged row(s) leave another DD target while being dragged
61782 * @param {Grid} this
61783 * @param {Roo.GridDD} dd The drag drop object
61784 * @param {String} targetId The target drag drop object
61785 * @param {event} e The raw browser event
61790 * Fires when a row is rendered, so you can change add a style to it.
61791 * @param {GridView} gridview The grid view
61792 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
61798 * Fires when the grid is rendered
61799 * @param {Grid} grid
61804 * Fires when a date is selected
61805 * @param {DatePicker} this
61806 * @param {Date} date The selected date
61810 * @event monthchange
61811 * Fires when the displayed month changes
61812 * @param {DatePicker} this
61813 * @param {Date} date The selected month
61815 'monthchange': true,
61817 * @event evententer
61818 * Fires when mouse over an event
61819 * @param {Calendar} this
61820 * @param {event} Event
61822 'evententer': true,
61824 * @event eventleave
61825 * Fires when the mouse leaves an
61826 * @param {Calendar} this
61829 'eventleave': true,
61831 * @event eventclick
61832 * Fires when the mouse click an
61833 * @param {Calendar} this
61836 'eventclick': true,
61838 * @event eventrender
61839 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
61840 * @param {Calendar} this
61841 * @param {data} data to be modified
61843 'eventrender': true
61847 Roo.grid.Grid.superclass.constructor.call(this);
61848 this.on('render', function() {
61849 this.view.el.addClass('x-grid-cal');
61851 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
61855 if (!Roo.grid.Calendar.style) {
61856 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
61859 '.x-grid-cal .x-grid-col' : {
61860 height: 'auto !important',
61861 'vertical-align': 'top'
61863 '.x-grid-cal .fc-event-hori' : {
61874 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
61876 * @cfg {Store} eventStore The store that loads events.
61881 activeDate : false,
61884 monitorWindowResize : false,
61887 resizeColumns : function() {
61888 var col = (this.view.el.getWidth() / 7) - 3;
61889 // loop through cols, and setWidth
61890 for(var i =0 ; i < 7 ; i++){
61891 this.cm.setColumnWidth(i, col);
61894 setDate :function(date) {
61896 Roo.log('setDate?');
61898 this.resizeColumns();
61899 var vd = this.activeDate;
61900 this.activeDate = date;
61901 // if(vd && this.el){
61902 // var t = date.getTime();
61903 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
61904 // Roo.log('using add remove');
61906 // this.fireEvent('monthchange', this, date);
61908 // this.cells.removeClass("fc-state-highlight");
61909 // this.cells.each(function(c){
61910 // if(c.dateValue == t){
61911 // c.addClass("fc-state-highlight");
61912 // setTimeout(function(){
61913 // try{c.dom.firstChild.focus();}catch(e){}
61923 var days = date.getDaysInMonth();
61925 var firstOfMonth = date.getFirstDateOfMonth();
61926 var startingPos = firstOfMonth.getDay()-this.startDay;
61928 if(startingPos < this.startDay){
61932 var pm = date.add(Date.MONTH, -1);
61933 var prevStart = pm.getDaysInMonth()-startingPos;
61937 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
61939 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
61940 //this.cells.addClassOnOver('fc-state-hover');
61942 var cells = this.cells.elements;
61943 var textEls = this.textNodes;
61945 //Roo.each(cells, function(cell){
61946 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
61949 days += startingPos;
61951 // convert everything to numbers so it's fast
61952 var day = 86400000;
61953 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
61956 //Roo.log(prevStart);
61958 var today = new Date().clearTime().getTime();
61959 var sel = date.clearTime().getTime();
61960 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
61961 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
61962 var ddMatch = this.disabledDatesRE;
61963 var ddText = this.disabledDatesText;
61964 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
61965 var ddaysText = this.disabledDaysText;
61966 var format = this.format;
61968 var setCellClass = function(cal, cell){
61970 //Roo.log('set Cell Class');
61972 var t = d.getTime();
61977 cell.dateValue = t;
61979 cell.className += " fc-today";
61980 cell.className += " fc-state-highlight";
61981 cell.title = cal.todayText;
61984 // disable highlight in other month..
61985 cell.className += " fc-state-highlight";
61990 //cell.className = " fc-state-disabled";
61991 cell.title = cal.minText;
61995 //cell.className = " fc-state-disabled";
61996 cell.title = cal.maxText;
62000 if(ddays.indexOf(d.getDay()) != -1){
62001 // cell.title = ddaysText;
62002 // cell.className = " fc-state-disabled";
62005 if(ddMatch && format){
62006 var fvalue = d.dateFormat(format);
62007 if(ddMatch.test(fvalue)){
62008 cell.title = ddText.replace("%0", fvalue);
62009 cell.className = " fc-state-disabled";
62013 if (!cell.initialClassName) {
62014 cell.initialClassName = cell.dom.className;
62017 cell.dom.className = cell.initialClassName + ' ' + cell.className;
62022 for(; i < startingPos; i++) {
62023 cells[i].dayName = (++prevStart);
62024 Roo.log(textEls[i]);
62025 d.setDate(d.getDate()+1);
62027 //cells[i].className = "fc-past fc-other-month";
62028 setCellClass(this, cells[i]);
62033 for(; i < days; i++){
62034 intDay = i - startingPos + 1;
62035 cells[i].dayName = (intDay);
62036 d.setDate(d.getDate()+1);
62038 cells[i].className = ''; // "x-date-active";
62039 setCellClass(this, cells[i]);
62043 for(; i < 42; i++) {
62044 //textEls[i].innerHTML = (++extraDays);
62046 d.setDate(d.getDate()+1);
62047 cells[i].dayName = (++extraDays);
62048 cells[i].className = "fc-future fc-other-month";
62049 setCellClass(this, cells[i]);
62052 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
62054 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
62056 // this will cause all the cells to mis
62059 for (var r = 0;r < 6;r++) {
62060 for (var c =0;c < 7;c++) {
62061 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
62065 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
62066 for(i=0;i<cells.length;i++) {
62068 this.cells.elements[i].dayName = cells[i].dayName ;
62069 this.cells.elements[i].className = cells[i].className;
62070 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
62071 this.cells.elements[i].title = cells[i].title ;
62072 this.cells.elements[i].dateValue = cells[i].dateValue ;
62078 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
62079 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
62081 ////if(totalRows != 6){
62082 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
62083 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
62086 this.fireEvent('monthchange', this, date);
62091 * Returns the grid's SelectionModel.
62092 * @return {SelectionModel}
62094 getSelectionModel : function(){
62095 if(!this.selModel){
62096 this.selModel = new Roo.grid.CellSelectionModel();
62098 return this.selModel;
62102 this.eventStore.load()
62108 findCell : function(dt) {
62109 dt = dt.clearTime().getTime();
62111 this.cells.each(function(c){
62112 //Roo.log("check " +c.dateValue + '?=' + dt);
62113 if(c.dateValue == dt){
62123 findCells : function(rec) {
62124 var s = rec.data.start_dt.clone().clearTime().getTime();
62126 var e= rec.data.end_dt.clone().clearTime().getTime();
62129 this.cells.each(function(c){
62130 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
62132 if(c.dateValue > e){
62135 if(c.dateValue < s){
62144 findBestRow: function(cells)
62148 for (var i =0 ; i < cells.length;i++) {
62149 ret = Math.max(cells[i].rows || 0,ret);
62156 addItem : function(rec)
62158 // look for vertical location slot in
62159 var cells = this.findCells(rec);
62161 rec.row = this.findBestRow(cells);
62163 // work out the location.
62167 for(var i =0; i < cells.length; i++) {
62175 if (crow.start.getY() == cells[i].getY()) {
62177 crow.end = cells[i];
62193 for (var i = 0; i < cells.length;i++) {
62194 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
62201 clearEvents: function() {
62203 if (!this.eventStore.getCount()) {
62206 // reset number of rows in cells.
62207 Roo.each(this.cells.elements, function(c){
62211 this.eventStore.each(function(e) {
62212 this.clearEvent(e);
62217 clearEvent : function(ev)
62220 Roo.each(ev.els, function(el) {
62221 el.un('mouseenter' ,this.onEventEnter, this);
62222 el.un('mouseleave' ,this.onEventLeave, this);
62230 renderEvent : function(ev,ctr) {
62232 ctr = this.view.el.select('.fc-event-container',true).first();
62236 this.clearEvent(ev);
62242 var cells = ev.cells;
62243 var rows = ev.rows;
62244 this.fireEvent('eventrender', this, ev);
62246 for(var i =0; i < rows.length; i++) {
62250 cls += ' fc-event-start';
62252 if ((i+1) == rows.length) {
62253 cls += ' fc-event-end';
62256 //Roo.log(ev.data);
62257 // how many rows should it span..
62258 var cg = this.eventTmpl.append(ctr,Roo.apply({
62261 }, ev.data) , true);
62264 cg.on('mouseenter' ,this.onEventEnter, this, ev);
62265 cg.on('mouseleave' ,this.onEventLeave, this, ev);
62266 cg.on('click', this.onEventClick, this, ev);
62270 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
62271 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
62274 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
62275 cg.setWidth(ebox.right - sbox.x -2);
62279 renderEvents: function()
62281 // first make sure there is enough space..
62283 if (!this.eventTmpl) {
62284 this.eventTmpl = new Roo.Template(
62285 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
62286 '<div class="fc-event-inner">' +
62287 '<span class="fc-event-time">{time}</span>' +
62288 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
62290 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
62298 this.cells.each(function(c) {
62299 //Roo.log(c.select('.fc-day-content div',true).first());
62300 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
62303 var ctr = this.view.el.select('.fc-event-container',true).first();
62306 this.eventStore.each(function(ev){
62308 this.renderEvent(ev);
62312 this.view.layout();
62316 onEventEnter: function (e, el,event,d) {
62317 this.fireEvent('evententer', this, el, event);
62320 onEventLeave: function (e, el,event,d) {
62321 this.fireEvent('eventleave', this, el, event);
62324 onEventClick: function (e, el,event,d) {
62325 this.fireEvent('eventclick', this, el, event);
62328 onMonthChange: function () {
62332 onLoad: function () {
62334 //Roo.log('calendar onload');
62336 if(this.eventStore.getCount() > 0){
62340 this.eventStore.each(function(d){
62345 if (typeof(add.end_dt) == 'undefined') {
62346 Roo.log("Missing End time in calendar data: ");
62350 if (typeof(add.start_dt) == 'undefined') {
62351 Roo.log("Missing Start time in calendar data: ");
62355 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
62356 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
62357 add.id = add.id || d.id;
62358 add.title = add.title || '??';
62366 this.renderEvents();
62376 render : function ()
62380 if (!this.view.el.hasClass('course-timesheet')) {
62381 this.view.el.addClass('course-timesheet');
62383 if (this.tsStyle) {
62388 Roo.log(_this.grid.view.el.getWidth());
62391 this.tsStyle = Roo.util.CSS.createStyleSheet({
62392 '.course-timesheet .x-grid-row' : {
62395 '.x-grid-row td' : {
62396 'vertical-align' : 0
62398 '.course-edit-link' : {
62400 'text-overflow' : 'ellipsis',
62401 'overflow' : 'hidden',
62402 'white-space' : 'nowrap',
62403 'cursor' : 'pointer'
62408 '.de-act-sup-link' : {
62409 'color' : 'purple',
62410 'text-decoration' : 'line-through'
62414 'text-decoration' : 'line-through'
62416 '.course-timesheet .course-highlight' : {
62417 'border-top-style': 'dashed !important',
62418 'border-bottom-bottom': 'dashed !important'
62420 '.course-timesheet .course-item' : {
62421 'font-family' : 'tahoma, arial, helvetica',
62422 'font-size' : '11px',
62423 'overflow' : 'hidden',
62424 'padding-left' : '10px',
62425 'padding-right' : '10px',
62426 'padding-top' : '10px'
62434 monitorWindowResize : false,
62435 cellrenderer : function(v,x,r)
62440 xtype: 'CellSelectionModel',
62447 beforeload : function (_self, options)
62449 options.params = options.params || {};
62450 options.params._month = _this.monthField.getValue();
62451 options.params.limit = 9999;
62452 options.params['sort'] = 'when_dt';
62453 options.params['dir'] = 'ASC';
62454 this.proxy.loadResponse = this.loadResponse;
62456 //this.addColumns();
62458 load : function (_self, records, options)
62460 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
62461 // if you click on the translation.. you can edit it...
62462 var el = Roo.get(this);
62463 var id = el.dom.getAttribute('data-id');
62464 var d = el.dom.getAttribute('data-date');
62465 var t = el.dom.getAttribute('data-time');
62466 //var id = this.child('span').dom.textContent;
62469 Pman.Dialog.CourseCalendar.show({
62473 productitem_active : id ? 1 : 0
62475 _this.grid.ds.load({});
62480 _this.panel.fireEvent('resize', [ '', '' ]);
62483 loadResponse : function(o, success, response){
62484 // this is overridden on before load..
62486 Roo.log("our code?");
62487 //Roo.log(success);
62488 //Roo.log(response)
62489 delete this.activeRequest;
62491 this.fireEvent("loadexception", this, o, response);
62492 o.request.callback.call(o.request.scope, null, o.request.arg, false);
62497 result = o.reader.read(response);
62499 Roo.log("load exception?");
62500 this.fireEvent("loadexception", this, o, response, e);
62501 o.request.callback.call(o.request.scope, null, o.request.arg, false);
62504 Roo.log("ready...");
62505 // loop through result.records;
62506 // and set this.tdate[date] = [] << array of records..
62508 Roo.each(result.records, function(r){
62510 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
62511 _this.tdata[r.data.when_dt.format('j')] = [];
62513 _this.tdata[r.data.when_dt.format('j')].push(r.data);
62516 //Roo.log(_this.tdata);
62518 result.records = [];
62519 result.totalRecords = 6;
62521 // let's generate some duumy records for the rows.
62522 //var st = _this.dateField.getValue();
62524 // work out monday..
62525 //st = st.add(Date.DAY, -1 * st.format('w'));
62527 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
62529 var firstOfMonth = date.getFirstDayOfMonth();
62530 var days = date.getDaysInMonth();
62532 var firstAdded = false;
62533 for (var i = 0; i < result.totalRecords ; i++) {
62534 //var d= st.add(Date.DAY, i);
62537 for(var w = 0 ; w < 7 ; w++){
62538 if(!firstAdded && firstOfMonth != w){
62545 var dd = (d > 0 && d < 10) ? "0"+d : d;
62546 row['weekday'+w] = String.format(
62547 '<span style="font-size: 16px;"><b>{0}</b></span>'+
62548 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
62550 date.format('Y-m-')+dd
62553 if(typeof(_this.tdata[d]) != 'undefined'){
62554 Roo.each(_this.tdata[d], function(r){
62558 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
62559 if(r.parent_id*1>0){
62560 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
62563 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
62564 deactive = 'de-act-link';
62567 row['weekday'+w] += String.format(
62568 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
62570 r.product_id_name, //1
62571 r.when_dt.format('h:ia'), //2
62581 // only do this if something added..
62583 result.records.push(_this.grid.dataSource.reader.newRow(row));
62587 // push it twice. (second one with an hour..
62591 this.fireEvent("load", this, o, o.request.arg);
62592 o.request.callback.call(o.request.scope, result, o.request.arg, true);
62594 sortInfo : {field: 'when_dt', direction : 'ASC' },
62596 xtype: 'HttpProxy',
62599 url : baseURL + '/Roo/Shop_course.php'
62602 xtype: 'JsonReader',
62619 'name': 'parent_id',
62623 'name': 'product_id',
62627 'name': 'productitem_id',
62645 click : function (_self, e)
62647 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
62648 sd.setMonth(sd.getMonth()-1);
62649 _this.monthField.setValue(sd.format('Y-m-d'));
62650 _this.grid.ds.load({});
62656 xtype: 'Separator',
62660 xtype: 'MonthField',
62663 render : function (_self)
62665 _this.monthField = _self;
62666 // _this.monthField.set today
62668 select : function (combo, date)
62670 _this.grid.ds.load({});
62673 value : (function() { return new Date(); })()
62676 xtype: 'Separator',
62682 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
62692 click : function (_self, e)
62694 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
62695 sd.setMonth(sd.getMonth()+1);
62696 _this.monthField.setValue(sd.format('Y-m-d'));
62697 _this.grid.ds.load({});
62710 * Ext JS Library 1.1.1
62711 * Copyright(c) 2006-2007, Ext JS, LLC.
62713 * Originally Released Under LGPL - original licence link has changed is not relivant.
62716 * <script type="text/javascript">
62720 * @class Roo.LoadMask
62721 * A simple utility class for generically masking elements while loading data. If the element being masked has
62722 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
62723 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
62724 * element's UpdateManager load indicator and will be destroyed after the initial load.
62726 * Create a new LoadMask
62727 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
62728 * @param {Object} config The config object
62730 Roo.LoadMask = function(el, config){
62731 this.el = Roo.get(el);
62732 Roo.apply(this, config);
62734 this.store.on('beforeload', this.onBeforeLoad, this);
62735 this.store.on('load', this.onLoad, this);
62736 this.store.on('loadexception', this.onLoadException, this);
62737 this.removeMask = false;
62739 var um = this.el.getUpdateManager();
62740 um.showLoadIndicator = false; // disable the default indicator
62741 um.on('beforeupdate', this.onBeforeLoad, this);
62742 um.on('update', this.onLoad, this);
62743 um.on('failure', this.onLoad, this);
62744 this.removeMask = true;
62748 Roo.LoadMask.prototype = {
62750 * @cfg {Boolean} removeMask
62751 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
62752 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
62754 removeMask : false,
62756 * @cfg {String} msg
62757 * The text to display in a centered loading message box (defaults to 'Loading...')
62759 msg : 'Loading...',
62761 * @cfg {String} msgCls
62762 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
62764 msgCls : 'x-mask-loading',
62767 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
62773 * Disables the mask to prevent it from being displayed
62775 disable : function(){
62776 this.disabled = true;
62780 * Enables the mask so that it can be displayed
62782 enable : function(){
62783 this.disabled = false;
62786 onLoadException : function()
62788 Roo.log(arguments);
62790 if (typeof(arguments[3]) != 'undefined') {
62791 Roo.MessageBox.alert("Error loading",arguments[3]);
62795 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
62796 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
62803 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
62806 onLoad : function()
62808 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
62812 onBeforeLoad : function(){
62813 if(!this.disabled){
62814 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
62819 destroy : function(){
62821 this.store.un('beforeload', this.onBeforeLoad, this);
62822 this.store.un('load', this.onLoad, this);
62823 this.store.un('loadexception', this.onLoadException, this);
62825 var um = this.el.getUpdateManager();
62826 um.un('beforeupdate', this.onBeforeLoad, this);
62827 um.un('update', this.onLoad, this);
62828 um.un('failure', this.onLoad, this);
62833 * Ext JS Library 1.1.1
62834 * Copyright(c) 2006-2007, Ext JS, LLC.
62836 * Originally Released Under LGPL - original licence link has changed is not relivant.
62839 * <script type="text/javascript">
62844 * @class Roo.XTemplate
62845 * @extends Roo.Template
62846 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
62848 var t = new Roo.XTemplate(
62849 '<select name="{name}">',
62850 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
62854 // then append, applying the master template values
62857 * Supported features:
62862 {a_variable} - output encoded.
62863 {a_variable.format:("Y-m-d")} - call a method on the variable
62864 {a_variable:raw} - unencoded output
62865 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
62866 {a_variable:this.method_on_template(...)} - call a method on the template object.
62871 <tpl for="a_variable or condition.."></tpl>
62872 <tpl if="a_variable or condition"></tpl>
62873 <tpl exec="some javascript"></tpl>
62874 <tpl name="named_template"></tpl> (experimental)
62876 <tpl for="."></tpl> - just iterate the property..
62877 <tpl for=".."></tpl> - iterates with the parent (probably the template)
62881 Roo.XTemplate = function()
62883 Roo.XTemplate.superclass.constructor.apply(this, arguments);
62890 Roo.extend(Roo.XTemplate, Roo.Template, {
62893 * The various sub templates
62898 * basic tag replacing syntax
62901 * // you can fake an object call by doing this
62905 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
62908 * compile the template
62910 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
62913 compile: function()
62917 s = ['<tpl>', s, '</tpl>'].join('');
62919 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
62920 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
62921 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
62922 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
62923 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
62928 while(true == !!(m = s.match(re))){
62929 var forMatch = m[0].match(nameRe),
62930 ifMatch = m[0].match(ifRe),
62931 execMatch = m[0].match(execRe),
62932 namedMatch = m[0].match(namedRe),
62937 name = forMatch && forMatch[1] ? forMatch[1] : '';
62940 // if - puts fn into test..
62941 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
62943 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
62948 // exec - calls a function... returns empty if true is returned.
62949 exp = execMatch && execMatch[1] ? execMatch[1] : null;
62951 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
62959 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
62960 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
62961 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
62964 var uid = namedMatch ? namedMatch[1] : id;
62968 id: namedMatch ? namedMatch[1] : id,
62975 s = s.replace(m[0], '');
62977 s = s.replace(m[0], '{xtpl'+ id + '}');
62982 for(var i = tpls.length-1; i >= 0; --i){
62983 this.compileTpl(tpls[i]);
62984 this.tpls[tpls[i].id] = tpls[i];
62986 this.master = tpls[tpls.length-1];
62990 * same as applyTemplate, except it's done to one of the subTemplates
62991 * when using named templates, you can do:
62993 * var str = pl.applySubTemplate('your-name', values);
62996 * @param {Number} id of the template
62997 * @param {Object} values to apply to template
62998 * @param {Object} parent (normaly the instance of this object)
63000 applySubTemplate : function(id, values, parent)
63004 var t = this.tpls[id];
63008 if(t.test && !t.test.call(this, values, parent)){
63012 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
63013 Roo.log(e.toString());
63019 if(t.exec && t.exec.call(this, values, parent)){
63023 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
63024 Roo.log(e.toString());
63029 var vs = t.target ? t.target.call(this, values, parent) : values;
63030 parent = t.target ? values : parent;
63031 if(t.target && vs instanceof Array){
63033 for(var i = 0, len = vs.length; i < len; i++){
63034 buf[buf.length] = t.compiled.call(this, vs[i], parent);
63036 return buf.join('');
63038 return t.compiled.call(this, vs, parent);
63040 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
63041 Roo.log(e.toString());
63042 Roo.log(t.compiled);
63047 compileTpl : function(tpl)
63049 var fm = Roo.util.Format;
63050 var useF = this.disableFormats !== true;
63051 var sep = Roo.isGecko ? "+" : ",";
63052 var undef = function(str) {
63053 Roo.log("Property not found :" + str);
63057 var fn = function(m, name, format, args)
63059 //Roo.log(arguments);
63060 args = args ? args.replace(/\\'/g,"'") : args;
63061 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
63062 if (typeof(format) == 'undefined') {
63063 format= 'htmlEncode';
63065 if (format == 'raw' ) {
63069 if(name.substr(0, 4) == 'xtpl'){
63070 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
63073 // build an array of options to determine if value is undefined..
63075 // basically get 'xxxx.yyyy' then do
63076 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
63077 // (function () { Roo.log("Property not found"); return ''; })() :
63082 Roo.each(name.split('.'), function(st) {
63083 lookfor += (lookfor.length ? '.': '') + st;
63084 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
63087 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
63090 if(format && useF){
63092 args = args ? ',' + args : "";
63094 if(format.substr(0, 5) != "this."){
63095 format = "fm." + format + '(';
63097 format = 'this.call("'+ format.substr(5) + '", ';
63101 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
63105 // called with xxyx.yuu:(test,test)
63107 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
63109 // raw.. - :raw modifier..
63110 return "'"+ sep + udef_st + name + ")"+sep+"'";
63114 // branched to use + in gecko and [].join() in others
63116 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
63117 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
63120 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
63121 body.push(tpl.body.replace(/(\r\n|\n)/g,
63122 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
63123 body.push("'].join('');};};");
63124 body = body.join('');
63127 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
63129 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
63135 applyTemplate : function(values){
63136 return this.master.compiled.call(this, values, {});
63137 //var s = this.subs;
63140 apply : function(){
63141 return this.applyTemplate.apply(this, arguments);
63146 Roo.XTemplate.from = function(el){
63147 el = Roo.getDom(el);
63148 return new Roo.XTemplate(el.value || el.innerHTML);