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++) {
45055 if (indent !== false // indent==false preservies everything
45057 && ar[i].nodeType == 3
45058 && ar[i].nodeValue.length > 0
45059 && ar[i].nodeValue.match(/^\s+/)
45061 if (ret.length && ret[ret.length-1] == "\n" + indent) {
45062 ret.pop(); // remove line break from last?
45065 ret.push(" "); // add a space if i'm a text item with a space at the front, as tidy will strip spaces.
45067 if (indent !== false
45068 && ar[i].nodeType == 1 // element - and indent is not set...
45070 ret.push("\n" + indent);
45073 ret.push(this.tidy(ar[i], indent));
45074 // text + trailing indent
45075 if (indent !== false
45076 && ar[i].nodeType == 3
45077 && ar[i].nodeValue.length > 0
45078 && ar[i].nodeValue.match(/\s+$/)
45080 ret.push("\n" + indent);
45087 // what if all text?
45090 return ret.join('');
45095 attr : function(node)
45098 for(i = 0; i < node.attributes.length;i++) {
45100 // skip empty values?
45101 if (!node.attributes.item(i).value.length) {
45104 attr.push( node.attributes.item(i).name + '="' +
45105 Roo.util.Format.htmlEncode(node.attributes.item(i).value) + '"'
45108 return attr.length ? (' ' + attr.join(' ') ) : '';
45116 * @class Roo.htmleditor.KeyEnter
45117 * Handle Enter press..
45118 * @cfg {Roo.HtmlEditorCore} core the editor.
45120 * Create a new Filter.
45121 * @param {Object} config Configuration options
45126 Roo.htmleditor.KeyEnter = function(cfg) {
45127 Roo.apply(this, cfg);
45128 // this does not actually call walk as it's really just a abstract class
45130 Roo.get(this.core.doc.body).on('keypress', this.keypress, this);
45134 Roo.htmleditor.KeyEnter.prototype = {
45138 keypress : function(e) {
45139 if (e.charCode != 13) {
45142 e.preventDefault();
45143 // https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
45144 var doc = this.core.doc;
45146 var docFragment = doc.createDocumentFragment();
45149 var newEle = doc.createTextNode('\n');
45150 docFragment.appendChild(newEle);
45152 //add the br, or p, or something else
45153 newEle = doc.createElement('br');
45154 docFragment.appendChild(newEle);
45156 //make the br replace selection
45157 var range = this.core.win.getSelection().getRangeAt(0);
45158 range.deleteContents();
45159 range.insertNode(docFragment);
45161 //create a new range
45162 range = doc.createRange();
45163 range.setStartAfter(newEle);
45164 range.collapse(true);
45166 //make the cursor there
45167 var sel = this.core.win.getSelection();
45168 sel.removeAllRanges();
45169 sel.addRange(range);
45177 * <figure data-block="BlockFigure" contenteditable="false" role="group" style="text-align:left">' +
45178 <img data-name="image" src="{SRC}">' +
45179 <figcaption data-name="caption" contenteditable="true" style="text-align:left">XXXX</figcaption>
45184 -- add to document..
45185 new Roo.htmleditor.BlockFigure{
45186 image_src : 'http://www.google.com',
45189 -- load document, and search for elements of this...
45190 Roo.DomQuery.select('*[data-block])
45191 // loop each and call ctor ({node : xxx})
45192 -- html editor click
45193 ** see if parent has Element.findParent(*[data-block]);
45198 Roo.htmleditor.BlockFigure = function(cfg)
45201 this.readElement(cfg.node);
45202 this.updateElement(cfg.node);
45204 Roo.apply(this, cfg);
45207 Roo.htmleditor.BlockFigure.prototype = {
45214 text_align: 'left',
45219 // used by context menu
45221 context : { // ?? static really
45232 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45237 title: "Caption Align",
45238 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45249 * create a DomHelper friendly object - for use with
45250 * Roo.DomHelper.markup / overwrite / etc..
45252 toObject : function()
45257 src : this.image_src,
45260 if ((''+this.image_width).length) {
45261 img.width = this.image_width;
45263 if ((''+ this.height).length) {
45264 img.height = this.image_height;
45268 'data-block' : 'Figure',
45269 contenteditable : 'false',
45270 style : 'text-align:' + this.align,
45275 contenteditable : true,
45276 style : 'text-align:left',
45277 html : this.caption
45283 readElement : function(node)
45285 this.image_src = this.getVal(node, 'img', 'src');
45286 this.align = this.getVal(node, 'figure', 'style', 'text-align');
45287 this.caption = this.getVal(node, 'figcaption', 'html');
45288 this.text_align = this.getVal(node, 'figcaption', 'style','text-align');
45291 updateElement : function(node)
45293 Roo.DomHelper.overwrite(node, this.toObject());
45296 * convert to plain HTML for calling insertAtCursor..
45298 toHTML : function()
45300 return Roo.DomHelper.markup(this.toObject());
45303 getVal : function(node, tag, attr, style)
45306 if (n.tagName != tag.toUpperCase()) {
45307 // in theory we could do figure[3] << 3rd figure? or some more complex search..?
45308 // but kiss for now.
45309 n = node.getElementsByTagName(tag).item(0);
45311 if (attr == 'html') {
45312 return n.innerHTML;
45314 if (attr == 'style') {
45315 return Roo.get(n).getStyle(style);
45318 return Roo.get(n).attr(attr);
45329 //<script type="text/javascript">
45332 * Based Ext JS Library 1.1.1
45333 * Copyright(c) 2006-2007, Ext JS, LLC.
45339 * @class Roo.HtmlEditorCore
45340 * @extends Roo.Component
45341 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
45343 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45346 Roo.HtmlEditorCore = function(config){
45349 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
45354 * @event initialize
45355 * Fires when the editor is fully initialized (including the iframe)
45356 * @param {Roo.HtmlEditorCore} this
45361 * Fires when the editor is first receives the focus. Any insertion must wait
45362 * until after this event.
45363 * @param {Roo.HtmlEditorCore} this
45367 * @event beforesync
45368 * Fires before the textarea is updated with content from the editor iframe. Return false
45369 * to cancel the sync.
45370 * @param {Roo.HtmlEditorCore} this
45371 * @param {String} html
45375 * @event beforepush
45376 * Fires before the iframe editor is updated with content from the textarea. Return false
45377 * to cancel the push.
45378 * @param {Roo.HtmlEditorCore} this
45379 * @param {String} html
45384 * Fires when the textarea is updated with content from the editor iframe.
45385 * @param {Roo.HtmlEditorCore} this
45386 * @param {String} html
45391 * Fires when the iframe editor is updated with content from the textarea.
45392 * @param {Roo.HtmlEditorCore} this
45393 * @param {String} html
45398 * @event editorevent
45399 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45400 * @param {Roo.HtmlEditorCore} this
45406 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
45408 // defaults : white / black...
45409 this.applyBlacklists();
45416 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
45420 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
45426 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45431 * @cfg {Number} height (in pixels)
45435 * @cfg {Number} width (in pixels)
45440 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45443 stylesheets: false,
45446 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
45448 allowComments: false,
45452 // private properties
45453 validationEvent : false,
45455 initialized : false,
45457 sourceEditMode : false,
45458 onFocus : Roo.emptyFn,
45460 hideMode:'offsets',
45464 // blacklist + whitelisted elements..
45471 * Protected method that will not generally be called directly. It
45472 * is called when the editor initializes the iframe with HTML contents. Override this method if you
45473 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
45475 getDocMarkup : function(){
45479 // inherit styels from page...??
45480 if (this.stylesheets === false) {
45482 Roo.get(document.head).select('style').each(function(node) {
45483 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
45486 Roo.get(document.head).select('link').each(function(node) {
45487 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
45490 } else if (!this.stylesheets.length) {
45492 st = '<style type="text/css">' +
45493 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
45496 for (var i in this.stylesheets) {
45497 if (typeof(this.stylesheets[i]) != 'string') {
45500 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
45505 st += '<style type="text/css">' +
45506 'IMG { cursor: pointer } ' +
45509 var cls = 'roo-htmleditor-body';
45511 if(this.bodyCls.length){
45512 cls += ' ' + this.bodyCls;
45515 return '<html><head>' + st +
45516 //<style type="text/css">' +
45517 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
45519 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
45523 onRender : function(ct, position)
45526 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
45527 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
45530 this.el.dom.style.border = '0 none';
45531 this.el.dom.setAttribute('tabIndex', -1);
45532 this.el.addClass('x-hidden hide');
45536 if(Roo.isIE){ // fix IE 1px bogus margin
45537 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
45541 this.frameId = Roo.id();
45545 var iframe = this.owner.wrap.createChild({
45547 cls: 'form-control', // bootstrap..
45549 name: this.frameId,
45550 frameBorder : 'no',
45551 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
45556 this.iframe = iframe.dom;
45558 this.assignDocWin();
45560 this.doc.designMode = 'on';
45563 this.doc.write(this.getDocMarkup());
45567 var task = { // must defer to wait for browser to be ready
45569 //console.log("run task?" + this.doc.readyState);
45570 this.assignDocWin();
45571 if(this.doc.body || this.doc.readyState == 'complete'){
45573 this.doc.designMode="on";
45577 Roo.TaskMgr.stop(task);
45578 this.initEditor.defer(10, this);
45585 Roo.TaskMgr.start(task);
45590 onResize : function(w, h)
45592 Roo.log('resize: ' +w + ',' + h );
45593 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
45597 if(typeof w == 'number'){
45599 this.iframe.style.width = w + 'px';
45601 if(typeof h == 'number'){
45603 this.iframe.style.height = h + 'px';
45605 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
45612 * Toggles the editor between standard and source edit mode.
45613 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45615 toggleSourceEdit : function(sourceEditMode){
45617 this.sourceEditMode = sourceEditMode === true;
45619 if(this.sourceEditMode){
45621 Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']); //FIXME - what's the BS styles for these
45624 Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']);
45625 //this.iframe.className = '';
45628 //this.setSize(this.owner.wrap.getSize());
45629 //this.fireEvent('editmodechange', this, this.sourceEditMode);
45636 * Protected method that will not generally be called directly. If you need/want
45637 * custom HTML cleanup, this is the method you should override.
45638 * @param {String} html The HTML to be cleaned
45639 * return {String} The cleaned HTML
45641 cleanHtml : function(html){
45642 html = String(html);
45643 if(html.length > 5){
45644 if(Roo.isSafari){ // strip safari nonsense
45645 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
45648 if(html == ' '){
45655 * HTML Editor -> Textarea
45656 * Protected method that will not generally be called directly. Syncs the contents
45657 * of the editor iframe with the textarea.
45659 syncValue : function()
45661 Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)");
45662 if(this.initialized){
45663 var bd = (this.doc.body || this.doc.documentElement);
45664 //this.cleanUpPaste(); -- this is done else where and causes havoc..
45666 var div = document.createElement('div');
45667 div.innerHTML = bd.innerHTML;
45668 // remove content editable. (blocks)
45669 new Roo.htmleditor.FilterAttributes({node : div, attrib_black: [ 'contenteditable' ] });
45671 var html = div.innerHTML;
45673 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
45674 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
45676 html = '<div style="'+m[0]+'">' + html + '</div>';
45679 html = this.cleanHtml(html);
45680 // fix up the special chars.. normaly like back quotes in word...
45681 // however we do not want to do this with chinese..
45682 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
45684 var cc = match.charCodeAt();
45686 // Get the character value, handling surrogate pairs
45687 if (match.length == 2) {
45688 // It's a surrogate pair, calculate the Unicode code point
45689 var high = match.charCodeAt(0) - 0xD800;
45690 var low = match.charCodeAt(1) - 0xDC00;
45691 cc = (high * 0x400) + low + 0x10000;
45693 (cc >= 0x4E00 && cc < 0xA000 ) ||
45694 (cc >= 0x3400 && cc < 0x4E00 ) ||
45695 (cc >= 0xf900 && cc < 0xfb00 )
45700 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
45701 return "&#" + cc + ";";
45708 if(this.owner.fireEvent('beforesync', this, html) !== false){
45709 this.el.dom.value = html;
45710 this.owner.fireEvent('sync', this, html);
45716 * TEXTAREA -> EDITABLE
45717 * Protected method that will not generally be called directly. Pushes the value of the textarea
45718 * into the iframe editor.
45720 pushValue : function()
45722 Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)");
45723 if(this.initialized){
45724 var v = this.el.dom.value.trim();
45727 if(this.owner.fireEvent('beforepush', this, v) !== false){
45728 var d = (this.doc.body || this.doc.documentElement);
45730 //this.cleanUpPaste();
45731 this.el.dom.value = d.innerHTML;
45732 this.owner.fireEvent('push', this, v);
45735 Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) {
45736 var cls = Roo.htmleditor['Block' + Roo.get(e).attr('data-block')];
45737 if (typeof(cls) == 'undefined') {
45738 Roo.log("OOps missing block : " + 'Block' + Roo.get(e).attr('data-block'));
45741 new cls(e); /// should trigger update element
45749 deferFocus : function(){
45750 this.focus.defer(10, this);
45754 focus : function(){
45755 if(this.win && !this.sourceEditMode){
45762 assignDocWin: function()
45764 var iframe = this.iframe;
45767 this.doc = iframe.contentWindow.document;
45768 this.win = iframe.contentWindow;
45770 // if (!Roo.get(this.frameId)) {
45773 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
45774 // this.win = Roo.get(this.frameId).dom.contentWindow;
45776 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
45780 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
45781 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
45786 initEditor : function(){
45787 //console.log("INIT EDITOR");
45788 this.assignDocWin();
45792 this.doc.designMode="on";
45794 this.doc.write(this.getDocMarkup());
45797 var dbody = (this.doc.body || this.doc.documentElement);
45798 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
45799 // this copies styles from the containing element into thsi one..
45800 // not sure why we need all of this..
45801 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
45803 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
45804 //ss['background-attachment'] = 'fixed'; // w3c
45805 dbody.bgProperties = 'fixed'; // ie
45806 //Roo.DomHelper.applyStyles(dbody, ss);
45807 Roo.EventManager.on(this.doc, {
45808 //'mousedown': this.onEditorEvent,
45809 'mouseup': this.onEditorEvent,
45810 'dblclick': this.onEditorEvent,
45811 'click': this.onEditorEvent,
45812 'keyup': this.onEditorEvent,
45813 'paste': this.onPasteEvent,
45818 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
45820 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
45821 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
45823 this.initialized = true;
45826 // initialize special key events - enter
45827 new Roo.htmleditor.KeyEnter({core : this});
45831 this.owner.fireEvent('initialize', this);
45835 onPasteEvent : function(e,v) {
45836 // default behaveiour should be our local cleanup paste? (optional?)
45837 // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable..
45838 this.owner.fireEvent('paste', e, v);
45841 onDestroy : function(){
45847 //for (var i =0; i < this.toolbars.length;i++) {
45848 // // fixme - ask toolbars for heights?
45849 // this.toolbars[i].onDestroy();
45852 //this.wrap.dom.innerHTML = '';
45853 //this.wrap.remove();
45858 onFirstFocus : function(){
45860 this.assignDocWin();
45863 this.activated = true;
45866 if(Roo.isGecko){ // prevent silly gecko errors
45868 var s = this.win.getSelection();
45869 if(!s.focusNode || s.focusNode.nodeType != 3){
45870 var r = s.getRangeAt(0);
45871 r.selectNodeContents((this.doc.body || this.doc.documentElement));
45876 this.execCmd('useCSS', true);
45877 this.execCmd('styleWithCSS', false);
45880 this.owner.fireEvent('activate', this);
45884 adjustFont: function(btn){
45885 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
45886 //if(Roo.isSafari){ // safari
45889 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
45890 if(Roo.isSafari){ // safari
45891 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
45892 v = (v < 10) ? 10 : v;
45893 v = (v > 48) ? 48 : v;
45894 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
45899 v = Math.max(1, v+adjust);
45901 this.execCmd('FontSize', v );
45904 onEditorEvent : function(e)
45906 this.owner.fireEvent('editorevent', this, e);
45907 // this.updateToolbar();
45908 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
45911 insertTag : function(tg)
45913 // could be a bit smarter... -> wrap the current selected tRoo..
45914 if (tg.toLowerCase() == 'span' ||
45915 tg.toLowerCase() == 'code' ||
45916 tg.toLowerCase() == 'sup' ||
45917 tg.toLowerCase() == 'sub'
45920 range = this.createRange(this.getSelection());
45921 var wrappingNode = this.doc.createElement(tg.toLowerCase());
45922 wrappingNode.appendChild(range.extractContents());
45923 range.insertNode(wrappingNode);
45930 this.execCmd("formatblock", tg);
45934 insertText : function(txt)
45938 var range = this.createRange();
45939 range.deleteContents();
45940 //alert(Sender.getAttribute('label'));
45942 range.insertNode(this.doc.createTextNode(txt));
45948 * Executes a Midas editor command on the editor document and performs necessary focus and
45949 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
45950 * @param {String} cmd The Midas command
45951 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
45953 relayCmd : function(cmd, value){
45955 this.execCmd(cmd, value);
45956 this.owner.fireEvent('editorevent', this);
45957 //this.updateToolbar();
45958 this.owner.deferFocus();
45962 * Executes a Midas editor command directly on the editor document.
45963 * For visual commands, you should use {@link #relayCmd} instead.
45964 * <b>This should only be called after the editor is initialized.</b>
45965 * @param {String} cmd The Midas command
45966 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
45968 execCmd : function(cmd, value){
45969 this.doc.execCommand(cmd, false, value === undefined ? null : value);
45976 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
45978 * @param {String} text | dom node..
45980 insertAtCursor : function(text)
45983 if(!this.activated){
45989 var r = this.doc.selection.createRange();
46000 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
46004 // from jquery ui (MIT licenced)
46006 var win = this.win;
46008 if (win.getSelection && win.getSelection().getRangeAt) {
46009 range = win.getSelection().getRangeAt(0);
46010 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
46011 range.insertNode(node);
46012 } else if (win.document.selection && win.document.selection.createRange) {
46013 // no firefox support
46014 var txt = typeof(text) == 'string' ? text : text.outerHTML;
46015 win.document.selection.createRange().pasteHTML(txt);
46017 // no firefox support
46018 var txt = typeof(text) == 'string' ? text : text.outerHTML;
46019 this.execCmd('InsertHTML', txt);
46028 mozKeyPress : function(e){
46030 var c = e.getCharCode(), cmd;
46033 c = String.fromCharCode(c).toLowerCase();
46047 // this.cleanUpPaste.defer(100, this);
46055 e.preventDefault();
46063 fixKeys : function(){ // load time branching for fastest keydown performance
46065 return function(e){
46066 var k = e.getKey(), r;
46069 r = this.doc.selection.createRange();
46072 r.pasteHTML('    ');
46079 r = this.doc.selection.createRange();
46081 var target = r.parentElement();
46082 if(!target || target.tagName.toLowerCase() != 'li'){
46084 r.pasteHTML('<br/>');
46090 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
46091 // this.cleanUpPaste.defer(100, this);
46097 }else if(Roo.isOpera){
46098 return function(e){
46099 var k = e.getKey();
46103 this.execCmd('InsertHTML','    ');
46106 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
46107 // this.cleanUpPaste.defer(100, this);
46112 }else if(Roo.isSafari){
46113 return function(e){
46114 var k = e.getKey();
46118 this.execCmd('InsertText','\t');
46122 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
46123 // this.cleanUpPaste.defer(100, this);
46131 getAllAncestors: function()
46133 var p = this.getSelectedNode();
46136 a.push(p); // push blank onto stack..
46137 p = this.getParentElement();
46141 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
46145 a.push(this.doc.body);
46149 lastSelNode : false,
46152 getSelection : function()
46154 this.assignDocWin();
46155 return Roo.isIE ? this.doc.selection : this.win.getSelection();
46158 getSelectedNode: function()
46160 // this may only work on Gecko!!!
46162 // should we cache this!!!!
46167 var range = this.createRange(this.getSelection()).cloneRange();
46170 var parent = range.parentElement();
46172 var testRange = range.duplicate();
46173 testRange.moveToElementText(parent);
46174 if (testRange.inRange(range)) {
46177 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
46180 parent = parent.parentElement;
46185 // is ancestor a text element.
46186 var ac = range.commonAncestorContainer;
46187 if (ac.nodeType == 3) {
46188 ac = ac.parentNode;
46191 var ar = ac.childNodes;
46194 var other_nodes = [];
46195 var has_other_nodes = false;
46196 for (var i=0;i<ar.length;i++) {
46197 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
46200 // fullly contained node.
46202 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
46207 // probably selected..
46208 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
46209 other_nodes.push(ar[i]);
46213 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
46218 has_other_nodes = true;
46220 if (!nodes.length && other_nodes.length) {
46221 nodes= other_nodes;
46223 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
46229 createRange: function(sel)
46231 // this has strange effects when using with
46232 // top toolbar - not sure if it's a great idea.
46233 //this.editor.contentWindow.focus();
46234 if (typeof sel != "undefined") {
46236 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
46238 return this.doc.createRange();
46241 return this.doc.createRange();
46244 getParentElement: function()
46247 this.assignDocWin();
46248 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
46250 var range = this.createRange(sel);
46253 var p = range.commonAncestorContainer;
46254 while (p.nodeType == 3) { // text node
46265 * Range intersection.. the hard stuff...
46269 * [ -- selected range --- ]
46273 * if end is before start or hits it. fail.
46274 * if start is after end or hits it fail.
46276 * if either hits (but other is outside. - then it's not
46282 // @see http://www.thismuchiknow.co.uk/?p=64.
46283 rangeIntersectsNode : function(range, node)
46285 var nodeRange = node.ownerDocument.createRange();
46287 nodeRange.selectNode(node);
46289 nodeRange.selectNodeContents(node);
46292 var rangeStartRange = range.cloneRange();
46293 rangeStartRange.collapse(true);
46295 var rangeEndRange = range.cloneRange();
46296 rangeEndRange.collapse(false);
46298 var nodeStartRange = nodeRange.cloneRange();
46299 nodeStartRange.collapse(true);
46301 var nodeEndRange = nodeRange.cloneRange();
46302 nodeEndRange.collapse(false);
46304 return rangeStartRange.compareBoundaryPoints(
46305 Range.START_TO_START, nodeEndRange) == -1 &&
46306 rangeEndRange.compareBoundaryPoints(
46307 Range.START_TO_START, nodeStartRange) == 1;
46311 rangeCompareNode : function(range, node)
46313 var nodeRange = node.ownerDocument.createRange();
46315 nodeRange.selectNode(node);
46317 nodeRange.selectNodeContents(node);
46321 range.collapse(true);
46323 nodeRange.collapse(true);
46325 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
46326 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
46328 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
46330 var nodeIsBefore = ss == 1;
46331 var nodeIsAfter = ee == -1;
46333 if (nodeIsBefore && nodeIsAfter) {
46336 if (!nodeIsBefore && nodeIsAfter) {
46337 return 1; //right trailed.
46340 if (nodeIsBefore && !nodeIsAfter) {
46341 return 2; // left trailed.
46347 // private? - in a new class?
46348 cleanUpPaste : function()
46350 // cleans up the whole document..
46351 Roo.log('cleanuppaste');
46353 this.cleanUpChild(this.doc.body);
46354 var clean = this.cleanWordChars(this.doc.body.innerHTML);
46355 if (clean != this.doc.body.innerHTML) {
46356 this.doc.body.innerHTML = clean;
46361 cleanWordChars : function(input) {// change the chars to hex code
46362 var he = Roo.HtmlEditorCore;
46364 var output = input;
46365 Roo.each(he.swapCodes, function(sw) {
46366 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
46368 output = output.replace(swapper, sw[1]);
46378 cleanUpChild : function (node)
46381 new Roo.htmleditor.FilterComment({node : node});
46382 new Roo.htmleditor.FilterAttributes({
46384 attrib_black : this.ablack,
46385 attrib_clean : this.aclean,
46386 style_white : this.cwhite,
46387 style_black : this.cblack
46389 new Roo.htmleditor.FilterBlack({ node : node, tag : this.black});
46390 new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} );
46396 * Clean up MS wordisms...
46397 * @deprecated - use filter directly
46399 cleanWord : function(node)
46401 new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
46408 * @deprecated - use filters
46410 cleanTableWidths : function(node)
46412 new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
46419 applyBlacklists : function()
46421 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
46422 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
46424 this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean : Roo.HtmlEditorCore.aclean;
46425 this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack : Roo.HtmlEditorCore.ablack;
46426 this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove : Roo.HtmlEditorCore.tag_remove;
46430 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
46431 if (b.indexOf(tag) > -1) {
46434 this.white.push(tag);
46438 Roo.each(w, function(tag) {
46439 if (b.indexOf(tag) > -1) {
46442 if (this.white.indexOf(tag) > -1) {
46445 this.white.push(tag);
46450 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
46451 if (w.indexOf(tag) > -1) {
46454 this.black.push(tag);
46458 Roo.each(b, function(tag) {
46459 if (w.indexOf(tag) > -1) {
46462 if (this.black.indexOf(tag) > -1) {
46465 this.black.push(tag);
46470 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
46471 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
46475 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
46476 if (b.indexOf(tag) > -1) {
46479 this.cwhite.push(tag);
46483 Roo.each(w, function(tag) {
46484 if (b.indexOf(tag) > -1) {
46487 if (this.cwhite.indexOf(tag) > -1) {
46490 this.cwhite.push(tag);
46495 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
46496 if (w.indexOf(tag) > -1) {
46499 this.cblack.push(tag);
46503 Roo.each(b, function(tag) {
46504 if (w.indexOf(tag) > -1) {
46507 if (this.cblack.indexOf(tag) > -1) {
46510 this.cblack.push(tag);
46515 setStylesheets : function(stylesheets)
46517 if(typeof(stylesheets) == 'string'){
46518 Roo.get(this.iframe.contentDocument.head).createChild({
46520 rel : 'stylesheet',
46529 Roo.each(stylesheets, function(s) {
46534 Roo.get(_this.iframe.contentDocument.head).createChild({
46536 rel : 'stylesheet',
46545 removeStylesheets : function()
46549 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
46554 setStyle : function(style)
46556 Roo.get(this.iframe.contentDocument.head).createChild({
46565 // hide stuff that is not compatible
46579 * @event specialkey
46583 * @cfg {String} fieldClass @hide
46586 * @cfg {String} focusClass @hide
46589 * @cfg {String} autoCreate @hide
46592 * @cfg {String} inputType @hide
46595 * @cfg {String} invalidClass @hide
46598 * @cfg {String} invalidText @hide
46601 * @cfg {String} msgFx @hide
46604 * @cfg {String} validateOnBlur @hide
46608 Roo.HtmlEditorCore.white = [
46609 'area', 'br', 'img', 'input', 'hr', 'wbr',
46611 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
46612 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
46613 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
46614 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
46615 'table', 'ul', 'xmp',
46617 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
46620 'dir', 'menu', 'ol', 'ul', 'dl',
46626 Roo.HtmlEditorCore.black = [
46627 // 'embed', 'object', // enable - backend responsiblity to clean thiese
46629 'base', 'basefont', 'bgsound', 'blink', 'body',
46630 'frame', 'frameset', 'head', 'html', 'ilayer',
46631 'iframe', 'layer', 'link', 'meta', 'object',
46632 'script', 'style' ,'title', 'xml' // clean later..
46634 Roo.HtmlEditorCore.clean = [
46635 'script', 'style', 'title', 'xml'
46637 Roo.HtmlEditorCore.tag_remove = [
46642 Roo.HtmlEditorCore.ablack = [
46646 Roo.HtmlEditorCore.aclean = [
46647 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
46651 Roo.HtmlEditorCore.pwhite= [
46652 'http', 'https', 'mailto'
46655 // white listed style attributes.
46656 Roo.HtmlEditorCore.cwhite= [
46657 // 'text-align', /// default is to allow most things..
46663 // black listed style attributes.
46664 Roo.HtmlEditorCore.cblack= [
46665 // 'font-size' -- this can be set by the project
46669 Roo.HtmlEditorCore.swapCodes =[
46670 [ 8211, "–" ],
46671 [ 8212, "—" ],
46680 //<script type="text/javascript">
46683 * Ext JS Library 1.1.1
46684 * Copyright(c) 2006-2007, Ext JS, LLC.
46690 Roo.form.HtmlEditor = function(config){
46694 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
46696 if (!this.toolbars) {
46697 this.toolbars = [];
46699 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
46705 * @class Roo.form.HtmlEditor
46706 * @extends Roo.form.Field
46707 * Provides a lightweight HTML Editor component.
46709 * This has been tested on Fireforx / Chrome.. IE may not be so great..
46711 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
46712 * supported by this editor.</b><br/><br/>
46713 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
46714 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
46716 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
46718 * @cfg {Boolean} clearUp
46722 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
46727 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
46732 * @cfg {Number} height (in pixels)
46736 * @cfg {Number} width (in pixels)
46741 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets - this is usally a good idea rootURL + '/roojs1/css/undoreset.css', .
46744 stylesheets: false,
46748 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
46753 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
46759 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
46764 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
46769 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
46771 allowComments: false,
46773 * @cfg {string} bodyCls- default '' default classes to add to body of editable area - usually undoreset is a good start..
46782 // private properties
46783 validationEvent : false,
46785 initialized : false,
46788 onFocus : Roo.emptyFn,
46790 hideMode:'offsets',
46792 actionMode : 'container', // defaults to hiding it...
46794 defaultAutoCreate : { // modified by initCompnoent..
46796 style:"width:500px;height:300px;",
46797 autocomplete: "new-password"
46801 initComponent : function(){
46804 * @event initialize
46805 * Fires when the editor is fully initialized (including the iframe)
46806 * @param {HtmlEditor} this
46811 * Fires when the editor is first receives the focus. Any insertion must wait
46812 * until after this event.
46813 * @param {HtmlEditor} this
46817 * @event beforesync
46818 * Fires before the textarea is updated with content from the editor iframe. Return false
46819 * to cancel the sync.
46820 * @param {HtmlEditor} this
46821 * @param {String} html
46825 * @event beforepush
46826 * Fires before the iframe editor is updated with content from the textarea. Return false
46827 * to cancel the push.
46828 * @param {HtmlEditor} this
46829 * @param {String} html
46834 * Fires when the textarea is updated with content from the editor iframe.
46835 * @param {HtmlEditor} this
46836 * @param {String} html
46841 * Fires when the iframe editor is updated with content from the textarea.
46842 * @param {HtmlEditor} this
46843 * @param {String} html
46847 * @event editmodechange
46848 * Fires when the editor switches edit modes
46849 * @param {HtmlEditor} this
46850 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
46852 editmodechange: true,
46854 * @event editorevent
46855 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
46856 * @param {HtmlEditor} this
46860 * @event firstfocus
46861 * Fires when on first focus - needed by toolbars..
46862 * @param {HtmlEditor} this
46867 * Auto save the htmlEditor value as a file into Events
46868 * @param {HtmlEditor} this
46872 * @event savedpreview
46873 * preview the saved version of htmlEditor
46874 * @param {HtmlEditor} this
46876 savedpreview: true,
46879 * @event stylesheetsclick
46880 * Fires when press the Sytlesheets button
46881 * @param {Roo.HtmlEditorCore} this
46883 stylesheetsclick: true,
46886 * Fires when press user pastes into the editor
46887 * @param {Roo.HtmlEditorCore} this
46891 this.defaultAutoCreate = {
46893 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
46894 autocomplete: "new-password"
46899 * Protected method that will not generally be called directly. It
46900 * is called when the editor creates its toolbar. Override this method if you need to
46901 * add custom toolbar buttons.
46902 * @param {HtmlEditor} editor
46904 createToolbar : function(editor){
46905 Roo.log("create toolbars");
46906 if (!editor.toolbars || !editor.toolbars.length) {
46907 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
46910 for (var i =0 ; i < editor.toolbars.length;i++) {
46911 editor.toolbars[i] = Roo.factory(
46912 typeof(editor.toolbars[i]) == 'string' ?
46913 { xtype: editor.toolbars[i]} : editor.toolbars[i],
46914 Roo.form.HtmlEditor);
46915 editor.toolbars[i].init(editor);
46923 onRender : function(ct, position)
46926 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
46928 this.wrap = this.el.wrap({
46929 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
46932 this.editorcore.onRender(ct, position);
46934 if (this.resizable) {
46935 this.resizeEl = new Roo.Resizable(this.wrap, {
46939 minHeight : this.height,
46940 height: this.height,
46941 handles : this.resizable,
46944 resize : function(r, w, h) {
46945 _t.onResize(w,h); // -something
46951 this.createToolbar(this);
46955 this.setSize(this.wrap.getSize());
46957 if (this.resizeEl) {
46958 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
46959 // should trigger onReize..
46962 this.keyNav = new Roo.KeyNav(this.el, {
46964 "tab" : function(e){
46965 e.preventDefault();
46967 var value = this.getValue();
46969 var start = this.el.dom.selectionStart;
46970 var end = this.el.dom.selectionEnd;
46974 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
46975 this.el.dom.setSelectionRange(end + 1, end + 1);
46979 var f = value.substring(0, start).split("\t");
46981 if(f.pop().length != 0){
46985 this.setValue(f.join("\t") + value.substring(end));
46986 this.el.dom.setSelectionRange(start - 1, start - 1);
46990 "home" : function(e){
46991 e.preventDefault();
46993 var curr = this.el.dom.selectionStart;
46994 var lines = this.getValue().split("\n");
47001 this.el.dom.setSelectionRange(0, 0);
47007 for (var i = 0; i < lines.length;i++) {
47008 pos += lines[i].length;
47018 pos -= lines[i].length;
47024 this.el.dom.setSelectionRange(pos, pos);
47028 this.el.dom.selectionStart = pos;
47029 this.el.dom.selectionEnd = curr;
47032 "end" : function(e){
47033 e.preventDefault();
47035 var curr = this.el.dom.selectionStart;
47036 var lines = this.getValue().split("\n");
47043 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
47049 for (var i = 0; i < lines.length;i++) {
47051 pos += lines[i].length;
47065 this.el.dom.setSelectionRange(pos, pos);
47069 this.el.dom.selectionStart = curr;
47070 this.el.dom.selectionEnd = pos;
47075 doRelay : function(foo, bar, hname){
47076 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
47082 // if(this.autosave && this.w){
47083 // this.autoSaveFn = setInterval(this.autosave, 1000);
47088 onResize : function(w, h)
47090 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
47095 if(typeof w == 'number'){
47096 var aw = w - this.wrap.getFrameWidth('lr');
47097 this.el.setWidth(this.adjustWidth('textarea', aw));
47100 if(typeof h == 'number'){
47102 for (var i =0; i < this.toolbars.length;i++) {
47103 // fixme - ask toolbars for heights?
47104 tbh += this.toolbars[i].tb.el.getHeight();
47105 if (this.toolbars[i].footer) {
47106 tbh += this.toolbars[i].footer.el.getHeight();
47113 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
47114 ah -= 5; // knock a few pixes off for look..
47116 this.el.setHeight(this.adjustWidth('textarea', ah));
47120 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
47121 this.editorcore.onResize(ew,eh);
47126 * Toggles the editor between standard and source edit mode.
47127 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
47129 toggleSourceEdit : function(sourceEditMode)
47131 this.editorcore.toggleSourceEdit(sourceEditMode);
47133 if(this.editorcore.sourceEditMode){
47134 Roo.log('editor - showing textarea');
47137 // Roo.log(this.syncValue());
47138 this.editorcore.syncValue();
47139 this.el.removeClass('x-hidden');
47140 this.el.dom.removeAttribute('tabIndex');
47142 this.el.dom.scrollTop = 0;
47145 for (var i = 0; i < this.toolbars.length; i++) {
47146 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
47147 this.toolbars[i].tb.hide();
47148 this.toolbars[i].footer.hide();
47153 Roo.log('editor - hiding textarea');
47155 // Roo.log(this.pushValue());
47156 this.editorcore.pushValue();
47158 this.el.addClass('x-hidden');
47159 this.el.dom.setAttribute('tabIndex', -1);
47161 for (var i = 0; i < this.toolbars.length; i++) {
47162 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
47163 this.toolbars[i].tb.show();
47164 this.toolbars[i].footer.show();
47168 //this.deferFocus();
47171 this.setSize(this.wrap.getSize());
47172 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
47174 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
47177 // private (for BoxComponent)
47178 adjustSize : Roo.BoxComponent.prototype.adjustSize,
47180 // private (for BoxComponent)
47181 getResizeEl : function(){
47185 // private (for BoxComponent)
47186 getPositionEl : function(){
47191 initEvents : function(){
47192 this.originalValue = this.getValue();
47196 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
47199 markInvalid : Roo.emptyFn,
47201 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
47204 clearInvalid : Roo.emptyFn,
47206 setValue : function(v){
47207 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
47208 this.editorcore.pushValue();
47213 deferFocus : function(){
47214 this.focus.defer(10, this);
47218 focus : function(){
47219 this.editorcore.focus();
47225 onDestroy : function(){
47231 for (var i =0; i < this.toolbars.length;i++) {
47232 // fixme - ask toolbars for heights?
47233 this.toolbars[i].onDestroy();
47236 this.wrap.dom.innerHTML = '';
47237 this.wrap.remove();
47242 onFirstFocus : function(){
47243 //Roo.log("onFirstFocus");
47244 this.editorcore.onFirstFocus();
47245 for (var i =0; i < this.toolbars.length;i++) {
47246 this.toolbars[i].onFirstFocus();
47252 syncValue : function()
47254 this.editorcore.syncValue();
47257 pushValue : function()
47259 this.editorcore.pushValue();
47262 setStylesheets : function(stylesheets)
47264 this.editorcore.setStylesheets(stylesheets);
47267 removeStylesheets : function()
47269 this.editorcore.removeStylesheets();
47273 // hide stuff that is not compatible
47287 * @event specialkey
47291 * @cfg {String} fieldClass @hide
47294 * @cfg {String} focusClass @hide
47297 * @cfg {String} autoCreate @hide
47300 * @cfg {String} inputType @hide
47303 * @cfg {String} invalidClass @hide
47306 * @cfg {String} invalidText @hide
47309 * @cfg {String} msgFx @hide
47312 * @cfg {String} validateOnBlur @hide
47316 // <script type="text/javascript">
47319 * Ext JS Library 1.1.1
47320 * Copyright(c) 2006-2007, Ext JS, LLC.
47326 * @class Roo.form.HtmlEditorToolbar1
47331 new Roo.form.HtmlEditor({
47334 new Roo.form.HtmlEditorToolbar1({
47335 disable : { fonts: 1 , format: 1, ..., ... , ...],
47341 * @cfg {Object} disable List of elements to disable..
47342 * @cfg {Array} btns List of additional buttons.
47346 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
47349 Roo.form.HtmlEditor.ToolbarStandard = function(config)
47352 Roo.apply(this, config);
47354 // default disabled, based on 'good practice'..
47355 this.disable = this.disable || {};
47356 Roo.applyIf(this.disable, {
47359 specialElements : true
47363 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
47364 // dont call parent... till later.
47367 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
47374 editorcore : false,
47376 * @cfg {Object} disable List of toolbar elements to disable
47383 * @cfg {String} createLinkText The default text for the create link prompt
47385 createLinkText : 'Please enter the URL for the link:',
47387 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
47389 defaultLinkValue : 'http:/'+'/',
47393 * @cfg {Array} fontFamilies An array of available font families
47411 // "á" , ?? a acute?
47416 "°" // , // degrees
47418 // "é" , // e ecute
47419 // "ú" , // u ecute?
47422 specialElements : [
47424 text: "Insert Table",
47427 ihtml : '<table><tr><td>Cell</td></tr></table>'
47431 text: "Insert Image",
47434 ihtml : '<img src="about:blank"/>'
47443 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
47444 "input:submit", "input:button", "select", "textarea", "label" ],
47447 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
47449 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
47458 * @cfg {String} defaultFont default font to use.
47460 defaultFont: 'tahoma',
47462 fontSelect : false,
47465 formatCombo : false,
47467 init : function(editor)
47469 this.editor = editor;
47470 this.editorcore = editor.editorcore ? editor.editorcore : editor;
47471 var editorcore = this.editorcore;
47475 var fid = editorcore.frameId;
47477 function btn(id, toggle, handler){
47478 var xid = fid + '-'+ id ;
47482 cls : 'x-btn-icon x-edit-'+id,
47483 enableToggle:toggle !== false,
47484 scope: _t, // was editor...
47485 handler:handler||_t.relayBtnCmd,
47486 clickEvent:'mousedown',
47487 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47494 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47496 // stop form submits
47497 tb.el.on('click', function(e){
47498 e.preventDefault(); // what does this do?
47501 if(!this.disable.font) { // && !Roo.isSafari){
47502 /* why no safari for fonts
47503 editor.fontSelect = tb.el.createChild({
47506 cls:'x-font-select',
47507 html: this.createFontOptions()
47510 editor.fontSelect.on('change', function(){
47511 var font = editor.fontSelect.dom.value;
47512 editor.relayCmd('fontname', font);
47513 editor.deferFocus();
47517 editor.fontSelect.dom,
47523 if(!this.disable.formats){
47524 this.formatCombo = new Roo.form.ComboBox({
47525 store: new Roo.data.SimpleStore({
47528 data : this.formats // from states.js
47532 //autoCreate : {tag: "div", size: "20"},
47533 displayField:'tag',
47537 triggerAction: 'all',
47538 emptyText:'Add tag',
47539 selectOnFocus:true,
47542 'select': function(c, r, i) {
47543 editorcore.insertTag(r.get('tag'));
47549 tb.addField(this.formatCombo);
47553 if(!this.disable.format){
47558 btn('strikethrough')
47561 if(!this.disable.fontSize){
47566 btn('increasefontsize', false, editorcore.adjustFont),
47567 btn('decreasefontsize', false, editorcore.adjustFont)
47572 if(!this.disable.colors){
47575 id:editorcore.frameId +'-forecolor',
47576 cls:'x-btn-icon x-edit-forecolor',
47577 clickEvent:'mousedown',
47578 tooltip: this.buttonTips['forecolor'] || undefined,
47580 menu : new Roo.menu.ColorMenu({
47581 allowReselect: true,
47582 focus: Roo.emptyFn,
47585 selectHandler: function(cp, color){
47586 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
47587 editor.deferFocus();
47590 clickEvent:'mousedown'
47593 id:editorcore.frameId +'backcolor',
47594 cls:'x-btn-icon x-edit-backcolor',
47595 clickEvent:'mousedown',
47596 tooltip: this.buttonTips['backcolor'] || undefined,
47598 menu : new Roo.menu.ColorMenu({
47599 focus: Roo.emptyFn,
47602 allowReselect: true,
47603 selectHandler: function(cp, color){
47605 editorcore.execCmd('useCSS', false);
47606 editorcore.execCmd('hilitecolor', color);
47607 editorcore.execCmd('useCSS', true);
47608 editor.deferFocus();
47610 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
47611 Roo.isSafari || Roo.isIE ? '#'+color : color);
47612 editor.deferFocus();
47616 clickEvent:'mousedown'
47621 // now add all the items...
47624 if(!this.disable.alignments){
47627 btn('justifyleft'),
47628 btn('justifycenter'),
47629 btn('justifyright')
47633 //if(!Roo.isSafari){
47634 if(!this.disable.links){
47637 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
47641 if(!this.disable.lists){
47644 btn('insertorderedlist'),
47645 btn('insertunorderedlist')
47648 if(!this.disable.sourceEdit){
47651 btn('sourceedit', true, function(btn){
47652 this.toggleSourceEdit(btn.pressed);
47659 // special menu.. - needs to be tidied up..
47660 if (!this.disable.special) {
47663 cls: 'x-edit-none',
47669 for (var i =0; i < this.specialChars.length; i++) {
47670 smenu.menu.items.push({
47672 html: this.specialChars[i],
47673 handler: function(a,b) {
47674 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
47675 //editor.insertAtCursor(a.html);
47689 if (!this.disable.cleanStyles) {
47691 cls: 'x-btn-icon x-btn-clear',
47697 for (var i =0; i < this.cleanStyles.length; i++) {
47698 cmenu.menu.items.push({
47699 actiontype : this.cleanStyles[i],
47700 html: 'Remove ' + this.cleanStyles[i],
47701 handler: function(a,b) {
47704 var c = Roo.get(editorcore.doc.body);
47705 c.select('[style]').each(function(s) {
47706 s.dom.style.removeProperty(a.actiontype);
47708 editorcore.syncValue();
47713 cmenu.menu.items.push({
47714 actiontype : 'tablewidths',
47715 html: 'Remove Table Widths',
47716 handler: function(a,b) {
47717 editorcore.cleanTableWidths();
47718 editorcore.syncValue();
47722 cmenu.menu.items.push({
47723 actiontype : 'word',
47724 html: 'Remove MS Word Formating',
47725 handler: function(a,b) {
47726 editorcore.cleanWord();
47727 editorcore.syncValue();
47732 cmenu.menu.items.push({
47733 actiontype : 'all',
47734 html: 'Remove All Styles',
47735 handler: function(a,b) {
47737 var c = Roo.get(editorcore.doc.body);
47738 c.select('[style]').each(function(s) {
47739 s.dom.removeAttribute('style');
47741 editorcore.syncValue();
47746 cmenu.menu.items.push({
47747 actiontype : 'all',
47748 html: 'Remove All CSS Classes',
47749 handler: function(a,b) {
47751 var c = Roo.get(editorcore.doc.body);
47752 c.select('[class]').each(function(s) {
47753 s.dom.removeAttribute('class');
47755 editorcore.cleanWord();
47756 editorcore.syncValue();
47761 cmenu.menu.items.push({
47762 actiontype : 'tidy',
47763 html: 'Tidy HTML Source',
47764 handler: function(a,b) {
47765 new Roo.htmleditor.Tidy(editorcore.doc.body);
47766 editorcore.syncValue();
47775 if (!this.disable.specialElements) {
47778 cls: 'x-edit-none',
47783 for (var i =0; i < this.specialElements.length; i++) {
47784 semenu.menu.items.push(
47786 handler: function(a,b) {
47787 editor.insertAtCursor(this.ihtml);
47789 }, this.specialElements[i])
47801 for(var i =0; i< this.btns.length;i++) {
47802 var b = Roo.factory(this.btns[i],Roo.form);
47803 b.cls = 'x-edit-none';
47805 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
47806 b.cls += ' x-init-enable';
47809 b.scope = editorcore;
47817 // disable everything...
47819 this.tb.items.each(function(item){
47822 item.id != editorcore.frameId+ '-sourceedit' &&
47823 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
47829 this.rendered = true;
47831 // the all the btns;
47832 editor.on('editorevent', this.updateToolbar, this);
47833 // other toolbars need to implement this..
47834 //editor.on('editmodechange', this.updateToolbar, this);
47838 relayBtnCmd : function(btn) {
47839 this.editorcore.relayCmd(btn.cmd);
47841 // private used internally
47842 createLink : function(){
47843 Roo.log("create link?");
47844 var url = prompt(this.createLinkText, this.defaultLinkValue);
47845 if(url && url != 'http:/'+'/'){
47846 this.editorcore.relayCmd('createlink', url);
47852 * Protected method that will not generally be called directly. It triggers
47853 * a toolbar update by reading the markup state of the current selection in the editor.
47855 updateToolbar: function(){
47857 if(!this.editorcore.activated){
47858 this.editor.onFirstFocus();
47862 var btns = this.tb.items.map,
47863 doc = this.editorcore.doc,
47864 frameId = this.editorcore.frameId;
47866 if(!this.disable.font && !Roo.isSafari){
47868 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
47869 if(name != this.fontSelect.dom.value){
47870 this.fontSelect.dom.value = name;
47874 if(!this.disable.format){
47875 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
47876 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
47877 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
47878 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
47880 if(!this.disable.alignments){
47881 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
47882 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
47883 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
47885 if(!Roo.isSafari && !this.disable.lists){
47886 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
47887 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
47890 var ans = this.editorcore.getAllAncestors();
47891 if (this.formatCombo) {
47894 var store = this.formatCombo.store;
47895 this.formatCombo.setValue("");
47896 for (var i =0; i < ans.length;i++) {
47897 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
47899 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
47907 // hides menus... - so this cant be on a menu...
47908 Roo.menu.MenuMgr.hideAll();
47910 //this.editorsyncValue();
47914 createFontOptions : function(){
47915 var buf = [], fs = this.fontFamilies, ff, lc;
47919 for(var i = 0, len = fs.length; i< len; i++){
47921 lc = ff.toLowerCase();
47923 '<option value="',lc,'" style="font-family:',ff,';"',
47924 (this.defaultFont == lc ? ' selected="true">' : '>'),
47929 return buf.join('');
47932 toggleSourceEdit : function(sourceEditMode){
47934 Roo.log("toolbar toogle");
47935 if(sourceEditMode === undefined){
47936 sourceEditMode = !this.sourceEditMode;
47938 this.sourceEditMode = sourceEditMode === true;
47939 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
47940 // just toggle the button?
47941 if(btn.pressed !== this.sourceEditMode){
47942 btn.toggle(this.sourceEditMode);
47946 if(sourceEditMode){
47947 Roo.log("disabling buttons");
47948 this.tb.items.each(function(item){
47949 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
47955 Roo.log("enabling buttons");
47956 if(this.editorcore.initialized){
47957 this.tb.items.each(function(item){
47963 Roo.log("calling toggole on editor");
47964 // tell the editor that it's been pressed..
47965 this.editor.toggleSourceEdit(sourceEditMode);
47969 * Object collection of toolbar tooltips for the buttons in the editor. The key
47970 * is the command id associated with that button and the value is a valid QuickTips object.
47975 title: 'Bold (Ctrl+B)',
47976 text: 'Make the selected text bold.',
47977 cls: 'x-html-editor-tip'
47980 title: 'Italic (Ctrl+I)',
47981 text: 'Make the selected text italic.',
47982 cls: 'x-html-editor-tip'
47990 title: 'Bold (Ctrl+B)',
47991 text: 'Make the selected text bold.',
47992 cls: 'x-html-editor-tip'
47995 title: 'Italic (Ctrl+I)',
47996 text: 'Make the selected text italic.',
47997 cls: 'x-html-editor-tip'
48000 title: 'Underline (Ctrl+U)',
48001 text: 'Underline the selected text.',
48002 cls: 'x-html-editor-tip'
48005 title: 'Strikethrough',
48006 text: 'Strikethrough the selected text.',
48007 cls: 'x-html-editor-tip'
48009 increasefontsize : {
48010 title: 'Grow Text',
48011 text: 'Increase the font size.',
48012 cls: 'x-html-editor-tip'
48014 decreasefontsize : {
48015 title: 'Shrink Text',
48016 text: 'Decrease the font size.',
48017 cls: 'x-html-editor-tip'
48020 title: 'Text Highlight Color',
48021 text: 'Change the background color of the selected text.',
48022 cls: 'x-html-editor-tip'
48025 title: 'Font Color',
48026 text: 'Change the color of the selected text.',
48027 cls: 'x-html-editor-tip'
48030 title: 'Align Text Left',
48031 text: 'Align text to the left.',
48032 cls: 'x-html-editor-tip'
48035 title: 'Center Text',
48036 text: 'Center text in the editor.',
48037 cls: 'x-html-editor-tip'
48040 title: 'Align Text Right',
48041 text: 'Align text to the right.',
48042 cls: 'x-html-editor-tip'
48044 insertunorderedlist : {
48045 title: 'Bullet List',
48046 text: 'Start a bulleted list.',
48047 cls: 'x-html-editor-tip'
48049 insertorderedlist : {
48050 title: 'Numbered List',
48051 text: 'Start a numbered list.',
48052 cls: 'x-html-editor-tip'
48055 title: 'Hyperlink',
48056 text: 'Make the selected text a hyperlink.',
48057 cls: 'x-html-editor-tip'
48060 title: 'Source Edit',
48061 text: 'Switch to source editing mode.',
48062 cls: 'x-html-editor-tip'
48066 onDestroy : function(){
48069 this.tb.items.each(function(item){
48071 item.menu.removeAll();
48073 item.menu.el.destroy();
48081 onFirstFocus: function() {
48082 this.tb.items.each(function(item){
48091 // <script type="text/javascript">
48094 * Ext JS Library 1.1.1
48095 * Copyright(c) 2006-2007, Ext JS, LLC.
48102 * @class Roo.form.HtmlEditor.ToolbarContext
48107 new Roo.form.HtmlEditor({
48110 { xtype: 'ToolbarStandard', styles : {} }
48111 { xtype: 'ToolbarContext', disable : {} }
48117 * @config : {Object} disable List of elements to disable.. (not done yet.)
48118 * @config : {Object} styles Map of styles available.
48122 Roo.form.HtmlEditor.ToolbarContext = function(config)
48125 Roo.apply(this, config);
48126 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
48127 // dont call parent... till later.
48128 this.styles = this.styles || {};
48133 Roo.form.HtmlEditor.ToolbarContext.types = {
48145 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
48167 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
48219 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
48224 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
48234 style : 'fontFamily',
48235 displayField: 'display',
48236 optname : 'font-family',
48285 // should we really allow this??
48286 // should this just be
48298 style : 'fontFamily',
48299 displayField: 'display',
48300 optname : 'font-family',
48307 style : 'fontFamily',
48308 displayField: 'display',
48309 optname : 'font-family',
48316 style : 'fontFamily',
48317 displayField: 'display',
48318 optname : 'font-family',
48329 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
48330 Roo.form.HtmlEditor.ToolbarContext.stores = false;
48332 Roo.form.HtmlEditor.ToolbarContext.options = {
48334 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
48335 [ 'Courier New', 'Courier New'],
48336 [ 'Tahoma', 'Tahoma'],
48337 [ 'Times New Roman,serif', 'Times'],
48338 [ 'Verdana','Verdana' ]
48342 // fixme - these need to be configurable..
48345 //Roo.form.HtmlEditor.ToolbarContext.types
48348 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
48355 editorcore : false,
48357 * @cfg {Object} disable List of toolbar elements to disable
48362 * @cfg {Object} styles List of styles
48363 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
48365 * These must be defined in the page, so they get rendered correctly..
48376 init : function(editor)
48378 this.editor = editor;
48379 this.editorcore = editor.editorcore ? editor.editorcore : editor;
48380 var editorcore = this.editorcore;
48382 var fid = editorcore.frameId;
48384 function btn(id, toggle, handler){
48385 var xid = fid + '-'+ id ;
48389 cls : 'x-btn-icon x-edit-'+id,
48390 enableToggle:toggle !== false,
48391 scope: editorcore, // was editor...
48392 handler:handler||editorcore.relayBtnCmd,
48393 clickEvent:'mousedown',
48394 tooltip: etb.buttonTips[id] || undefined, ///tips ???
48398 // create a new element.
48399 var wdiv = editor.wrap.createChild({
48401 }, editor.wrap.dom.firstChild.nextSibling, true);
48403 // can we do this more than once??
48405 // stop form submits
48408 // disable everything...
48409 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
48410 this.toolbars = {};
48412 for (var i in ty) {
48414 this.toolbars[i] = this.buildToolbar(ty[i],i);
48416 this.tb = this.toolbars.BODY;
48418 this.buildFooter();
48419 this.footer.show();
48420 editor.on('hide', function( ) { this.footer.hide() }, this);
48421 editor.on('show', function( ) { this.footer.show() }, this);
48424 this.rendered = true;
48426 // the all the btns;
48427 editor.on('editorevent', this.updateToolbar, this);
48428 // other toolbars need to implement this..
48429 //editor.on('editmodechange', this.updateToolbar, this);
48435 * Protected method that will not generally be called directly. It triggers
48436 * a toolbar update by reading the markup state of the current selection in the editor.
48438 * Note you can force an update by calling on('editorevent', scope, false)
48440 updateToolbar: function(editor,ev,sel){
48443 // capture mouse up - this is handy for selecting images..
48444 // perhaps should go somewhere else...
48445 if(!this.editorcore.activated){
48446 this.editor.onFirstFocus();
48452 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
48453 // selectNode - might want to handle IE?
48455 (ev.type == 'mouseup' || ev.type == 'click' ) &&
48456 ev.target && ev.target.tagName == 'IMG') {
48457 // they have click on an image...
48458 // let's see if we can change the selection...
48461 var nodeRange = sel.ownerDocument.createRange();
48463 nodeRange.selectNode(sel);
48465 nodeRange.selectNodeContents(sel);
48467 //nodeRange.collapse(true);
48468 var s = this.editorcore.win.getSelection();
48469 s.removeAllRanges();
48470 s.addRange(nodeRange);
48474 //var updateFooter = sel ? false : true;
48477 var ans = this.editorcore.getAllAncestors();
48480 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
48483 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
48484 sel = sel ? sel : this.editorcore.doc.body;
48485 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
48488 // pick a menu that exists..
48489 var tn = sel.tagName.toUpperCase();
48490 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
48492 tn = sel.tagName.toUpperCase();
48494 var lastSel = this.tb.selectedNode;
48496 this.tb.selectedNode = sel;
48498 // if current menu does not match..
48500 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
48503 ///console.log("show: " + tn);
48504 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
48507 this.tb.items.first().el.innerHTML = tn + ': ';
48510 // update attributes
48511 if (this.tb.fields) {
48512 this.tb.fields.each(function(e) {
48514 e.setValue(sel.style[e.stylename]);
48517 e.setValue(sel.getAttribute(e.attrname));
48521 var hasStyles = false;
48522 for(var i in this.styles) {
48529 var st = this.tb.fields.item(0);
48531 st.store.removeAll();
48534 var cn = sel.className.split(/\s+/);
48537 if (this.styles['*']) {
48539 Roo.each(this.styles['*'], function(v) {
48540 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
48543 if (this.styles[tn]) {
48544 Roo.each(this.styles[tn], function(v) {
48545 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
48549 st.store.loadData(avs);
48553 // flag our selected Node.
48554 this.tb.selectedNode = sel;
48557 Roo.menu.MenuMgr.hideAll();
48561 ///if (!updateFooter) {
48562 //this.footDisp.dom.innerHTML = '';
48565 // update the footer
48569 this.footerEls = ans.reverse();
48570 Roo.each(this.footerEls, function(a,i) {
48571 if (!a) { return; }
48572 html += html.length ? ' > ' : '';
48574 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
48579 var sz = this.footDisp.up('td').getSize();
48580 this.footDisp.dom.style.width = (sz.width -10) + 'px';
48581 this.footDisp.dom.style.marginLeft = '5px';
48583 this.footDisp.dom.style.overflow = 'hidden';
48585 this.footDisp.dom.innerHTML = html;
48587 //this.editorsyncValue();
48594 onDestroy : function(){
48597 this.tb.items.each(function(item){
48599 item.menu.removeAll();
48601 item.menu.el.destroy();
48609 onFirstFocus: function() {
48610 // need to do this for all the toolbars..
48611 this.tb.items.each(function(item){
48615 buildToolbar: function(tlist, nm)
48617 var editor = this.editor;
48618 var editorcore = this.editorcore;
48619 // create a new element.
48620 var wdiv = editor.wrap.createChild({
48622 }, editor.wrap.dom.firstChild.nextSibling, true);
48625 var tb = new Roo.Toolbar(wdiv);
48628 tb.add(nm+ ": ");
48631 for(var i in this.styles) {
48636 if (styles && styles.length) {
48638 // this needs a multi-select checkbox...
48639 tb.addField( new Roo.form.ComboBox({
48640 store: new Roo.data.SimpleStore({
48642 fields: ['val', 'selected'],
48645 name : '-roo-edit-className',
48646 attrname : 'className',
48647 displayField: 'val',
48651 triggerAction: 'all',
48652 emptyText:'Select Style',
48653 selectOnFocus:true,
48656 'select': function(c, r, i) {
48657 // initial support only for on class per el..
48658 tb.selectedNode.className = r ? r.get('val') : '';
48659 editorcore.syncValue();
48666 var tbc = Roo.form.HtmlEditor.ToolbarContext;
48667 var tbops = tbc.options;
48669 for (var i in tlist) {
48671 var item = tlist[i];
48672 tb.add(item.title + ": ");
48675 //optname == used so you can configure the options available..
48676 var opts = item.opts ? item.opts : false;
48677 if (item.optname) {
48678 opts = tbops[item.optname];
48683 // opts == pulldown..
48684 tb.addField( new Roo.form.ComboBox({
48685 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
48687 fields: ['val', 'display'],
48690 name : '-roo-edit-' + i,
48692 stylename : item.style ? item.style : false,
48693 displayField: item.displayField ? item.displayField : 'val',
48694 valueField : 'val',
48696 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
48698 triggerAction: 'all',
48699 emptyText:'Select',
48700 selectOnFocus:true,
48701 width: item.width ? item.width : 130,
48703 'select': function(c, r, i) {
48705 tb.selectedNode.style[c.stylename] = r.get('val');
48709 tb.selectedNode.removeAttribute(c.attrname);
48712 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
48721 tb.addField( new Roo.form.TextField({
48724 //allowBlank:false,
48729 tb.addField( new Roo.form.TextField({
48730 name: '-roo-edit-' + i,
48737 'change' : function(f, nv, ov) {
48738 tb.selectedNode.setAttribute(f.attrname, nv);
48739 editorcore.syncValue();
48752 text: 'Stylesheets',
48755 click : function ()
48757 _this.editor.fireEvent('stylesheetsclick', _this.editor);
48765 text: 'Remove Tag', // remove the tag, and puts the children outside...
48768 click : function ()
48771 // undo does not work.
48773 var sn = tb.selectedNode;
48775 var pn = sn.parentNode;
48777 // what i'm going to select after deleting..
48778 var stn = sn.childNodes[0] || sn.nextSibling || sn.previousSibling || pn;
48781 stn = sn.nextSibling;
48783 var en = sn.childNodes[sn.childNodes.length - 1 ];
48784 while (sn.childNodes.length) {
48785 var node = sn.childNodes[0];
48786 sn.removeChild(node);
48788 pn.insertBefore(node, sn);
48791 pn.removeChild(sn);
48792 var range = editorcore.createRange();
48794 range.setStart(stn,0);
48795 range.setEnd(en,0); //????
48796 //range.selectNode(sel);
48799 var selection = editorcore.getSelection();
48800 selection.removeAllRanges();
48801 selection.addRange(range);
48805 //_this.updateToolbar(null, null, pn);
48806 _this.updateToolbar(null, null, null);
48807 _this.footDisp.dom.innerHTML = '';
48817 tb.el.on('click', function(e){
48818 e.preventDefault(); // what does this do?
48820 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
48823 // dont need to disable them... as they will get hidden
48828 buildFooter : function()
48831 var fel = this.editor.wrap.createChild();
48832 this.footer = new Roo.Toolbar(fel);
48833 // toolbar has scrolly on left / right?
48834 var footDisp= new Roo.Toolbar.Fill();
48840 handler : function() {
48841 _t.footDisp.scrollTo('left',0,true)
48845 this.footer.add( footDisp );
48850 handler : function() {
48852 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
48856 var fel = Roo.get(footDisp.el);
48857 fel.addClass('x-editor-context');
48858 this.footDispWrap = fel;
48859 this.footDispWrap.overflow = 'hidden';
48861 this.footDisp = fel.createChild();
48862 this.footDispWrap.on('click', this.onContextClick, this)
48866 onContextClick : function (ev,dom)
48868 ev.preventDefault();
48869 var cn = dom.className;
48871 if (!cn.match(/x-ed-loc-/)) {
48874 var n = cn.split('-').pop();
48875 var ans = this.footerEls;
48879 var range = this.editorcore.createRange();
48881 range.selectNodeContents(sel);
48882 //range.selectNode(sel);
48885 var selection = this.editorcore.getSelection();
48886 selection.removeAllRanges();
48887 selection.addRange(range);
48891 this.updateToolbar(null, null, sel);
48908 * Ext JS Library 1.1.1
48909 * Copyright(c) 2006-2007, Ext JS, LLC.
48911 * Originally Released Under LGPL - original licence link has changed is not relivant.
48914 * <script type="text/javascript">
48918 * @class Roo.form.BasicForm
48919 * @extends Roo.util.Observable
48920 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
48922 * @param {String/HTMLElement/Roo.Element} el The form element or its id
48923 * @param {Object} config Configuration options
48925 Roo.form.BasicForm = function(el, config){
48926 this.allItems = [];
48927 this.childForms = [];
48928 Roo.apply(this, config);
48930 * The Roo.form.Field items in this form.
48931 * @type MixedCollection
48935 this.items = new Roo.util.MixedCollection(false, function(o){
48936 return o.id || (o.id = Roo.id());
48940 * @event beforeaction
48941 * Fires before any action is performed. Return false to cancel the action.
48942 * @param {Form} this
48943 * @param {Action} action The action to be performed
48945 beforeaction: true,
48947 * @event actionfailed
48948 * Fires when an action fails.
48949 * @param {Form} this
48950 * @param {Action} action The action that failed
48952 actionfailed : true,
48954 * @event actioncomplete
48955 * Fires when an action is completed.
48956 * @param {Form} this
48957 * @param {Action} action The action that completed
48959 actioncomplete : true
48964 Roo.form.BasicForm.superclass.constructor.call(this);
48966 Roo.form.BasicForm.popover.apply();
48969 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
48971 * @cfg {String} method
48972 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
48975 * @cfg {DataReader} reader
48976 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
48977 * This is optional as there is built-in support for processing JSON.
48980 * @cfg {DataReader} errorReader
48981 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
48982 * This is completely optional as there is built-in support for processing JSON.
48985 * @cfg {String} url
48986 * The URL to use for form actions if one isn't supplied in the action options.
48989 * @cfg {Boolean} fileUpload
48990 * Set to true if this form is a file upload.
48994 * @cfg {Object} baseParams
48995 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
49000 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
49005 activeAction : null,
49008 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
49009 * or setValues() data instead of when the form was first created.
49011 trackResetOnLoad : false,
49015 * childForms - used for multi-tab forms
49018 childForms : false,
49021 * allItems - full list of fields.
49027 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
49028 * element by passing it or its id or mask the form itself by passing in true.
49031 waitMsgTarget : false,
49036 disableMask : false,
49039 * @cfg {Boolean} errorMask (true|false) default false
49044 * @cfg {Number} maskOffset Default 100
49049 initEl : function(el){
49050 this.el = Roo.get(el);
49051 this.id = this.el.id || Roo.id();
49052 this.el.on('submit', this.onSubmit, this);
49053 this.el.addClass('x-form');
49057 onSubmit : function(e){
49062 * Returns true if client-side validation on the form is successful.
49065 isValid : function(){
49067 var target = false;
49068 this.items.each(function(f){
49075 if(!target && f.el.isVisible(true)){
49080 if(this.errorMask && !valid){
49081 Roo.form.BasicForm.popover.mask(this, target);
49087 * Returns array of invalid form fields.
49091 invalidFields : function()
49094 this.items.each(function(f){
49107 * DEPRICATED Returns true if any fields in this form have changed since their original load.
49110 isDirty : function(){
49112 this.items.each(function(f){
49122 * Returns true if any fields in this form have changed since their original load. (New version)
49126 hasChanged : function()
49129 this.items.each(function(f){
49130 if(f.hasChanged()){
49139 * Resets all hasChanged to 'false' -
49140 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
49141 * So hasChanged storage is only to be used for this purpose
49144 resetHasChanged : function()
49146 this.items.each(function(f){
49147 f.resetHasChanged();
49154 * Performs a predefined action (submit or load) or custom actions you define on this form.
49155 * @param {String} actionName The name of the action type
49156 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
49157 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
49158 * accept other config options):
49160 Property Type Description
49161 ---------------- --------------- ----------------------------------------------------------------------------------
49162 url String The url for the action (defaults to the form's url)
49163 method String The form method to use (defaults to the form's method, or POST if not defined)
49164 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
49165 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
49166 validate the form on the client (defaults to false)
49168 * @return {BasicForm} this
49170 doAction : function(action, options){
49171 if(typeof action == 'string'){
49172 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
49174 if(this.fireEvent('beforeaction', this, action) !== false){
49175 this.beforeAction(action);
49176 action.run.defer(100, action);
49182 * Shortcut to do a submit action.
49183 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
49184 * @return {BasicForm} this
49186 submit : function(options){
49187 this.doAction('submit', options);
49192 * Shortcut to do a load action.
49193 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
49194 * @return {BasicForm} this
49196 load : function(options){
49197 this.doAction('load', options);
49202 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
49203 * @param {Record} record The record to edit
49204 * @return {BasicForm} this
49206 updateRecord : function(record){
49207 record.beginEdit();
49208 var fs = record.fields;
49209 fs.each(function(f){
49210 var field = this.findField(f.name);
49212 record.set(f.name, field.getValue());
49220 * Loads an Roo.data.Record into this form.
49221 * @param {Record} record The record to load
49222 * @return {BasicForm} this
49224 loadRecord : function(record){
49225 this.setValues(record.data);
49230 beforeAction : function(action){
49231 var o = action.options;
49233 if(!this.disableMask) {
49234 if(this.waitMsgTarget === true){
49235 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
49236 }else if(this.waitMsgTarget){
49237 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
49238 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
49240 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
49248 afterAction : function(action, success){
49249 this.activeAction = null;
49250 var o = action.options;
49252 if(!this.disableMask) {
49253 if(this.waitMsgTarget === true){
49255 }else if(this.waitMsgTarget){
49256 this.waitMsgTarget.unmask();
49258 Roo.MessageBox.updateProgress(1);
49259 Roo.MessageBox.hide();
49267 Roo.callback(o.success, o.scope, [this, action]);
49268 this.fireEvent('actioncomplete', this, action);
49272 // failure condition..
49273 // we have a scenario where updates need confirming.
49274 // eg. if a locking scenario exists..
49275 // we look for { errors : { needs_confirm : true }} in the response.
49277 (typeof(action.result) != 'undefined') &&
49278 (typeof(action.result.errors) != 'undefined') &&
49279 (typeof(action.result.errors.needs_confirm) != 'undefined')
49282 Roo.MessageBox.confirm(
49283 "Change requires confirmation",
49284 action.result.errorMsg,
49289 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
49299 Roo.callback(o.failure, o.scope, [this, action]);
49300 // show an error message if no failed handler is set..
49301 if (!this.hasListener('actionfailed')) {
49302 Roo.MessageBox.alert("Error",
49303 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
49304 action.result.errorMsg :
49305 "Saving Failed, please check your entries or try again"
49309 this.fireEvent('actionfailed', this, action);
49315 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
49316 * @param {String} id The value to search for
49319 findField : function(id){
49320 var field = this.items.get(id);
49322 this.items.each(function(f){
49323 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
49329 return field || null;
49333 * Add a secondary form to this one,
49334 * Used to provide tabbed forms. One form is primary, with hidden values
49335 * which mirror the elements from the other forms.
49337 * @param {Roo.form.Form} form to add.
49340 addForm : function(form)
49343 if (this.childForms.indexOf(form) > -1) {
49347 this.childForms.push(form);
49349 Roo.each(form.allItems, function (fe) {
49351 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
49352 if (this.findField(n)) { // already added..
49355 var add = new Roo.form.Hidden({
49358 add.render(this.el);
49365 * Mark fields in this form invalid in bulk.
49366 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
49367 * @return {BasicForm} this
49369 markInvalid : function(errors){
49370 if(errors instanceof Array){
49371 for(var i = 0, len = errors.length; i < len; i++){
49372 var fieldError = errors[i];
49373 var f = this.findField(fieldError.id);
49375 f.markInvalid(fieldError.msg);
49381 if(typeof errors[id] != 'function' && (field = this.findField(id))){
49382 field.markInvalid(errors[id]);
49386 Roo.each(this.childForms || [], function (f) {
49387 f.markInvalid(errors);
49394 * Set values for fields in this form in bulk.
49395 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
49396 * @return {BasicForm} this
49398 setValues : function(values){
49399 if(values instanceof Array){ // array of objects
49400 for(var i = 0, len = values.length; i < len; i++){
49402 var f = this.findField(v.id);
49404 f.setValue(v.value);
49405 if(this.trackResetOnLoad){
49406 f.originalValue = f.getValue();
49410 }else{ // object hash
49413 if(typeof values[id] != 'function' && (field = this.findField(id))){
49415 if (field.setFromData &&
49416 field.valueField &&
49417 field.displayField &&
49418 // combos' with local stores can
49419 // be queried via setValue()
49420 // to set their value..
49421 (field.store && !field.store.isLocal)
49425 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
49426 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
49427 field.setFromData(sd);
49430 field.setValue(values[id]);
49434 if(this.trackResetOnLoad){
49435 field.originalValue = field.getValue();
49440 this.resetHasChanged();
49443 Roo.each(this.childForms || [], function (f) {
49444 f.setValues(values);
49445 f.resetHasChanged();
49452 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
49453 * they are returned as an array.
49454 * @param {Boolean} asString
49457 getValues : function(asString){
49458 if (this.childForms) {
49459 // copy values from the child forms
49460 Roo.each(this.childForms, function (f) {
49461 this.setValues(f.getValues());
49466 if (typeof(FormData) != 'undefined' && asString !== true) {
49467 // this relies on a 'recent' version of chrome apparently...
49469 var fd = (new FormData(this.el.dom)).entries();
49471 var ent = fd.next();
49472 while (!ent.done) {
49473 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
49484 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
49485 if(asString === true){
49488 return Roo.urlDecode(fs);
49492 * Returns the fields in this form as an object with key/value pairs.
49493 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
49496 getFieldValues : function(with_hidden)
49498 if (this.childForms) {
49499 // copy values from the child forms
49500 // should this call getFieldValues - probably not as we do not currently copy
49501 // hidden fields when we generate..
49502 Roo.each(this.childForms, function (f) {
49503 this.setValues(f.getValues());
49508 this.items.each(function(f){
49509 if (!f.getName()) {
49512 var v = f.getValue();
49513 if (f.inputType =='radio') {
49514 if (typeof(ret[f.getName()]) == 'undefined') {
49515 ret[f.getName()] = ''; // empty..
49518 if (!f.el.dom.checked) {
49522 v = f.el.dom.value;
49526 // not sure if this supported any more..
49527 if ((typeof(v) == 'object') && f.getRawValue) {
49528 v = f.getRawValue() ; // dates..
49530 // combo boxes where name != hiddenName...
49531 if (f.name != f.getName()) {
49532 ret[f.name] = f.getRawValue();
49534 ret[f.getName()] = v;
49541 * Clears all invalid messages in this form.
49542 * @return {BasicForm} this
49544 clearInvalid : function(){
49545 this.items.each(function(f){
49549 Roo.each(this.childForms || [], function (f) {
49558 * Resets this form.
49559 * @return {BasicForm} this
49561 reset : function(){
49562 this.items.each(function(f){
49566 Roo.each(this.childForms || [], function (f) {
49569 this.resetHasChanged();
49575 * Add Roo.form components to this form.
49576 * @param {Field} field1
49577 * @param {Field} field2 (optional)
49578 * @param {Field} etc (optional)
49579 * @return {BasicForm} this
49582 this.items.addAll(Array.prototype.slice.call(arguments, 0));
49588 * Removes a field from the items collection (does NOT remove its markup).
49589 * @param {Field} field
49590 * @return {BasicForm} this
49592 remove : function(field){
49593 this.items.remove(field);
49598 * Looks at the fields in this form, checks them for an id attribute,
49599 * and calls applyTo on the existing dom element with that id.
49600 * @return {BasicForm} this
49602 render : function(){
49603 this.items.each(function(f){
49604 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
49612 * Calls {@link Ext#apply} for all fields in this form with the passed object.
49613 * @param {Object} values
49614 * @return {BasicForm} this
49616 applyToFields : function(o){
49617 this.items.each(function(f){
49624 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
49625 * @param {Object} values
49626 * @return {BasicForm} this
49628 applyIfToFields : function(o){
49629 this.items.each(function(f){
49637 Roo.BasicForm = Roo.form.BasicForm;
49639 Roo.apply(Roo.form.BasicForm, {
49653 intervalID : false,
49659 if(this.isApplied){
49664 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
49665 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
49666 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
49667 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
49670 this.maskEl.top.enableDisplayMode("block");
49671 this.maskEl.left.enableDisplayMode("block");
49672 this.maskEl.bottom.enableDisplayMode("block");
49673 this.maskEl.right.enableDisplayMode("block");
49675 Roo.get(document.body).on('click', function(){
49679 Roo.get(document.body).on('touchstart', function(){
49683 this.isApplied = true
49686 mask : function(form, target)
49690 this.target = target;
49692 if(!this.form.errorMask || !target.el){
49696 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
49698 var ot = this.target.el.calcOffsetsTo(scrollable);
49700 var scrollTo = ot[1] - this.form.maskOffset;
49702 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
49704 scrollable.scrollTo('top', scrollTo);
49706 var el = this.target.wrap || this.target.el;
49708 var box = el.getBox();
49710 this.maskEl.top.setStyle('position', 'absolute');
49711 this.maskEl.top.setStyle('z-index', 10000);
49712 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
49713 this.maskEl.top.setLeft(0);
49714 this.maskEl.top.setTop(0);
49715 this.maskEl.top.show();
49717 this.maskEl.left.setStyle('position', 'absolute');
49718 this.maskEl.left.setStyle('z-index', 10000);
49719 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
49720 this.maskEl.left.setLeft(0);
49721 this.maskEl.left.setTop(box.y - this.padding);
49722 this.maskEl.left.show();
49724 this.maskEl.bottom.setStyle('position', 'absolute');
49725 this.maskEl.bottom.setStyle('z-index', 10000);
49726 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
49727 this.maskEl.bottom.setLeft(0);
49728 this.maskEl.bottom.setTop(box.bottom + this.padding);
49729 this.maskEl.bottom.show();
49731 this.maskEl.right.setStyle('position', 'absolute');
49732 this.maskEl.right.setStyle('z-index', 10000);
49733 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
49734 this.maskEl.right.setLeft(box.right + this.padding);
49735 this.maskEl.right.setTop(box.y - this.padding);
49736 this.maskEl.right.show();
49738 this.intervalID = window.setInterval(function() {
49739 Roo.form.BasicForm.popover.unmask();
49742 window.onwheel = function(){ return false;};
49744 (function(){ this.isMasked = true; }).defer(500, this);
49748 unmask : function()
49750 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
49754 this.maskEl.top.setStyle('position', 'absolute');
49755 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
49756 this.maskEl.top.hide();
49758 this.maskEl.left.setStyle('position', 'absolute');
49759 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
49760 this.maskEl.left.hide();
49762 this.maskEl.bottom.setStyle('position', 'absolute');
49763 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
49764 this.maskEl.bottom.hide();
49766 this.maskEl.right.setStyle('position', 'absolute');
49767 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
49768 this.maskEl.right.hide();
49770 window.onwheel = function(){ return true;};
49772 if(this.intervalID){
49773 window.clearInterval(this.intervalID);
49774 this.intervalID = false;
49777 this.isMasked = false;
49785 * Ext JS Library 1.1.1
49786 * Copyright(c) 2006-2007, Ext JS, LLC.
49788 * Originally Released Under LGPL - original licence link has changed is not relivant.
49791 * <script type="text/javascript">
49795 * @class Roo.form.Form
49796 * @extends Roo.form.BasicForm
49797 * @children Roo.form.Column Roo.form.FieldSet Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49798 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
49800 * @param {Object} config Configuration options
49802 Roo.form.Form = function(config){
49804 if (config.items) {
49805 xitems = config.items;
49806 delete config.items;
49810 Roo.form.Form.superclass.constructor.call(this, null, config);
49811 this.url = this.url || this.action;
49813 this.root = new Roo.form.Layout(Roo.applyIf({
49817 this.active = this.root;
49819 * Array of all the buttons that have been added to this form via {@link addButton}
49823 this.allItems = [];
49826 * @event clientvalidation
49827 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
49828 * @param {Form} this
49829 * @param {Boolean} valid true if the form has passed client-side validation
49831 clientvalidation: true,
49834 * Fires when the form is rendered
49835 * @param {Roo.form.Form} form
49840 if (this.progressUrl) {
49841 // push a hidden field onto the list of fields..
49845 name : 'UPLOAD_IDENTIFIER'
49850 Roo.each(xitems, this.addxtype, this);
49854 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
49856 * @cfg {Roo.Button} buttons[] buttons at bottom of form
49860 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
49863 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
49866 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
49868 buttonAlign:'center',
49871 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
49876 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
49877 * This property cascades to child containers if not set.
49882 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
49883 * fires a looping event with that state. This is required to bind buttons to the valid
49884 * state using the config value formBind:true on the button.
49886 monitorValid : false,
49889 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
49894 * @cfg {String} progressUrl - Url to return progress data
49897 progressUrl : false,
49899 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
49900 * sending a formdata with extra parameters - eg uploaded elements.
49906 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
49907 * fields are added and the column is closed. If no fields are passed the column remains open
49908 * until end() is called.
49909 * @param {Object} config The config to pass to the column
49910 * @param {Field} field1 (optional)
49911 * @param {Field} field2 (optional)
49912 * @param {Field} etc (optional)
49913 * @return Column The column container object
49915 column : function(c){
49916 var col = new Roo.form.Column(c);
49918 if(arguments.length > 1){ // duplicate code required because of Opera
49919 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
49926 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
49927 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
49928 * until end() is called.
49929 * @param {Object} config The config to pass to the fieldset
49930 * @param {Field} field1 (optional)
49931 * @param {Field} field2 (optional)
49932 * @param {Field} etc (optional)
49933 * @return FieldSet The fieldset container object
49935 fieldset : function(c){
49936 var fs = new Roo.form.FieldSet(c);
49938 if(arguments.length > 1){ // duplicate code required because of Opera
49939 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
49946 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
49947 * fields are added and the container is closed. If no fields are passed the container remains open
49948 * until end() is called.
49949 * @param {Object} config The config to pass to the Layout
49950 * @param {Field} field1 (optional)
49951 * @param {Field} field2 (optional)
49952 * @param {Field} etc (optional)
49953 * @return Layout The container object
49955 container : function(c){
49956 var l = new Roo.form.Layout(c);
49958 if(arguments.length > 1){ // duplicate code required because of Opera
49959 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
49966 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
49967 * @param {Object} container A Roo.form.Layout or subclass of Layout
49968 * @return {Form} this
49970 start : function(c){
49971 // cascade label info
49972 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
49973 this.active.stack.push(c);
49974 c.ownerCt = this.active;
49980 * Closes the current open container
49981 * @return {Form} this
49984 if(this.active == this.root){
49987 this.active = this.active.ownerCt;
49992 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
49993 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
49994 * as the label of the field.
49995 * @param {Field} field1
49996 * @param {Field} field2 (optional)
49997 * @param {Field} etc. (optional)
49998 * @return {Form} this
50001 this.active.stack.push.apply(this.active.stack, arguments);
50002 this.allItems.push.apply(this.allItems,arguments);
50004 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
50005 if(a[i].isFormField){
50010 Roo.form.Form.superclass.add.apply(this, r);
50020 * Find any element that has been added to a form, using it's ID or name
50021 * This can include framesets, columns etc. along with regular fields..
50022 * @param {String} id - id or name to find.
50024 * @return {Element} e - or false if nothing found.
50026 findbyId : function(id)
50032 Roo.each(this.allItems, function(f){
50033 if (f.id == id || f.name == id ){
50044 * Render this form into the passed container. This should only be called once!
50045 * @param {String/HTMLElement/Element} container The element this component should be rendered into
50046 * @return {Form} this
50048 render : function(ct)
50054 var o = this.autoCreate || {
50056 method : this.method || 'POST',
50057 id : this.id || Roo.id()
50059 this.initEl(ct.createChild(o));
50061 this.root.render(this.el);
50065 this.items.each(function(f){
50066 f.render('x-form-el-'+f.id);
50069 if(this.buttons.length > 0){
50070 // tables are required to maintain order and for correct IE layout
50071 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
50072 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
50073 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
50075 var tr = tb.getElementsByTagName('tr')[0];
50076 for(var i = 0, len = this.buttons.length; i < len; i++) {
50077 var b = this.buttons[i];
50078 var td = document.createElement('td');
50079 td.className = 'x-form-btn-td';
50080 b.render(tr.appendChild(td));
50083 if(this.monitorValid){ // initialize after render
50084 this.startMonitoring();
50086 this.fireEvent('rendered', this);
50091 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
50092 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
50093 * object or a valid Roo.DomHelper element config
50094 * @param {Function} handler The function called when the button is clicked
50095 * @param {Object} scope (optional) The scope of the handler function
50096 * @return {Roo.Button}
50098 addButton : function(config, handler, scope){
50102 minWidth: this.minButtonWidth,
50105 if(typeof config == "string"){
50108 Roo.apply(bc, config);
50110 var btn = new Roo.Button(null, bc);
50111 this.buttons.push(btn);
50116 * Adds a series of form elements (using the xtype property as the factory method.
50117 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
50118 * @param {Object} config
50121 addxtype : function()
50123 var ar = Array.prototype.slice.call(arguments, 0);
50125 for(var i = 0; i < ar.length; i++) {
50127 continue; // skip -- if this happends something invalid got sent, we
50128 // should ignore it, as basically that interface element will not show up
50129 // and that should be pretty obvious!!
50132 if (Roo.form[ar[i].xtype]) {
50134 var fe = Roo.factory(ar[i], Roo.form);
50140 fe.store.form = this;
50145 this.allItems.push(fe);
50146 if (fe.items && fe.addxtype) {
50147 fe.addxtype.apply(fe, fe.items);
50157 // console.log('adding ' + ar[i].xtype);
50159 if (ar[i].xtype == 'Button') {
50160 //console.log('adding button');
50161 //console.log(ar[i]);
50162 this.addButton(ar[i]);
50163 this.allItems.push(fe);
50167 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
50168 alert('end is not supported on xtype any more, use items');
50170 // //console.log('adding end');
50178 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
50179 * option "monitorValid"
50181 startMonitoring : function(){
50184 Roo.TaskMgr.start({
50185 run : this.bindHandler,
50186 interval : this.monitorPoll || 200,
50193 * Stops monitoring of the valid state of this form
50195 stopMonitoring : function(){
50196 this.bound = false;
50200 bindHandler : function(){
50202 return false; // stops binding
50205 this.items.each(function(f){
50206 if(!f.isValid(true)){
50211 for(var i = 0, len = this.buttons.length; i < len; i++){
50212 var btn = this.buttons[i];
50213 if(btn.formBind === true && btn.disabled === valid){
50214 btn.setDisabled(!valid);
50217 this.fireEvent('clientvalidation', this, valid);
50231 Roo.Form = Roo.form.Form;
50234 * Ext JS Library 1.1.1
50235 * Copyright(c) 2006-2007, Ext JS, LLC.
50237 * Originally Released Under LGPL - original licence link has changed is not relivant.
50240 * <script type="text/javascript">
50243 // as we use this in bootstrap.
50244 Roo.namespace('Roo.form');
50246 * @class Roo.form.Action
50247 * Internal Class used to handle form actions
50249 * @param {Roo.form.BasicForm} el The form element or its id
50250 * @param {Object} config Configuration options
50255 // define the action interface
50256 Roo.form.Action = function(form, options){
50258 this.options = options || {};
50261 * Client Validation Failed
50264 Roo.form.Action.CLIENT_INVALID = 'client';
50266 * Server Validation Failed
50269 Roo.form.Action.SERVER_INVALID = 'server';
50271 * Connect to Server Failed
50274 Roo.form.Action.CONNECT_FAILURE = 'connect';
50276 * Reading Data from Server Failed
50279 Roo.form.Action.LOAD_FAILURE = 'load';
50281 Roo.form.Action.prototype = {
50283 failureType : undefined,
50284 response : undefined,
50285 result : undefined,
50287 // interface method
50288 run : function(options){
50292 // interface method
50293 success : function(response){
50297 // interface method
50298 handleResponse : function(response){
50302 // default connection failure
50303 failure : function(response){
50305 this.response = response;
50306 this.failureType = Roo.form.Action.CONNECT_FAILURE;
50307 this.form.afterAction(this, false);
50310 processResponse : function(response){
50311 this.response = response;
50312 if(!response.responseText){
50315 this.result = this.handleResponse(response);
50316 return this.result;
50319 // utility functions used internally
50320 getUrl : function(appendParams){
50321 var url = this.options.url || this.form.url || this.form.el.dom.action;
50323 var p = this.getParams();
50325 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
50331 getMethod : function(){
50332 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
50335 getParams : function(){
50336 var bp = this.form.baseParams;
50337 var p = this.options.params;
50339 if(typeof p == "object"){
50340 p = Roo.urlEncode(Roo.applyIf(p, bp));
50341 }else if(typeof p == 'string' && bp){
50342 p += '&' + Roo.urlEncode(bp);
50345 p = Roo.urlEncode(bp);
50350 createCallback : function(){
50352 success: this.success,
50353 failure: this.failure,
50355 timeout: (this.form.timeout*1000),
50356 upload: this.form.fileUpload ? this.success : undefined
50361 Roo.form.Action.Submit = function(form, options){
50362 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
50365 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
50368 haveProgress : false,
50369 uploadComplete : false,
50371 // uploadProgress indicator.
50372 uploadProgress : function()
50374 if (!this.form.progressUrl) {
50378 if (!this.haveProgress) {
50379 Roo.MessageBox.progress("Uploading", "Uploading");
50381 if (this.uploadComplete) {
50382 Roo.MessageBox.hide();
50386 this.haveProgress = true;
50388 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
50390 var c = new Roo.data.Connection();
50392 url : this.form.progressUrl,
50397 success : function(req){
50398 //console.log(data);
50402 rdata = Roo.decode(req.responseText)
50404 Roo.log("Invalid data from server..");
50408 if (!rdata || !rdata.success) {
50410 Roo.MessageBox.alert(Roo.encode(rdata));
50413 var data = rdata.data;
50415 if (this.uploadComplete) {
50416 Roo.MessageBox.hide();
50421 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
50422 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
50425 this.uploadProgress.defer(2000,this);
50428 failure: function(data) {
50429 Roo.log('progress url failed ');
50440 // run get Values on the form, so it syncs any secondary forms.
50441 this.form.getValues();
50443 var o = this.options;
50444 var method = this.getMethod();
50445 var isPost = method == 'POST';
50446 if(o.clientValidation === false || this.form.isValid()){
50448 if (this.form.progressUrl) {
50449 this.form.findField('UPLOAD_IDENTIFIER').setValue(
50450 (new Date() * 1) + '' + Math.random());
50455 Roo.Ajax.request(Roo.apply(this.createCallback(), {
50456 form:this.form.el.dom,
50457 url:this.getUrl(!isPost),
50459 params:isPost ? this.getParams() : null,
50460 isUpload: this.form.fileUpload,
50461 formData : this.form.formData
50464 this.uploadProgress();
50466 }else if (o.clientValidation !== false){ // client validation failed
50467 this.failureType = Roo.form.Action.CLIENT_INVALID;
50468 this.form.afterAction(this, false);
50472 success : function(response)
50474 this.uploadComplete= true;
50475 if (this.haveProgress) {
50476 Roo.MessageBox.hide();
50480 var result = this.processResponse(response);
50481 if(result === true || result.success){
50482 this.form.afterAction(this, true);
50486 this.form.markInvalid(result.errors);
50487 this.failureType = Roo.form.Action.SERVER_INVALID;
50489 this.form.afterAction(this, false);
50491 failure : function(response)
50493 this.uploadComplete= true;
50494 if (this.haveProgress) {
50495 Roo.MessageBox.hide();
50498 this.response = response;
50499 this.failureType = Roo.form.Action.CONNECT_FAILURE;
50500 this.form.afterAction(this, false);
50503 handleResponse : function(response){
50504 if(this.form.errorReader){
50505 var rs = this.form.errorReader.read(response);
50508 for(var i = 0, len = rs.records.length; i < len; i++) {
50509 var r = rs.records[i];
50510 errors[i] = r.data;
50513 if(errors.length < 1){
50517 success : rs.success,
50523 ret = Roo.decode(response.responseText);
50527 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
50537 Roo.form.Action.Load = function(form, options){
50538 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
50539 this.reader = this.form.reader;
50542 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
50547 Roo.Ajax.request(Roo.apply(
50548 this.createCallback(), {
50549 method:this.getMethod(),
50550 url:this.getUrl(false),
50551 params:this.getParams()
50555 success : function(response){
50557 var result = this.processResponse(response);
50558 if(result === true || !result.success || !result.data){
50559 this.failureType = Roo.form.Action.LOAD_FAILURE;
50560 this.form.afterAction(this, false);
50563 this.form.clearInvalid();
50564 this.form.setValues(result.data);
50565 this.form.afterAction(this, true);
50568 handleResponse : function(response){
50569 if(this.form.reader){
50570 var rs = this.form.reader.read(response);
50571 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
50573 success : rs.success,
50577 return Roo.decode(response.responseText);
50581 Roo.form.Action.ACTION_TYPES = {
50582 'load' : Roo.form.Action.Load,
50583 'submit' : Roo.form.Action.Submit
50586 * Ext JS Library 1.1.1
50587 * Copyright(c) 2006-2007, Ext JS, LLC.
50589 * Originally Released Under LGPL - original licence link has changed is not relivant.
50592 * <script type="text/javascript">
50596 * @class Roo.form.Layout
50597 * @extends Roo.Component
50598 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
50599 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
50601 * @param {Object} config Configuration options
50603 Roo.form.Layout = function(config){
50605 if (config.items) {
50606 xitems = config.items;
50607 delete config.items;
50609 Roo.form.Layout.superclass.constructor.call(this, config);
50611 Roo.each(xitems, this.addxtype, this);
50615 Roo.extend(Roo.form.Layout, Roo.Component, {
50617 * @cfg {String/Object} autoCreate
50618 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
50621 * @cfg {String/Object/Function} style
50622 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
50623 * a function which returns such a specification.
50626 * @cfg {String} labelAlign
50627 * Valid values are "left," "top" and "right" (defaults to "left")
50630 * @cfg {Number} labelWidth
50631 * Fixed width in pixels of all field labels (defaults to undefined)
50634 * @cfg {Boolean} clear
50635 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
50639 * @cfg {String} labelSeparator
50640 * The separator to use after field labels (defaults to ':')
50642 labelSeparator : ':',
50644 * @cfg {Boolean} hideLabels
50645 * True to suppress the display of field labels in this layout (defaults to false)
50647 hideLabels : false,
50650 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
50655 onRender : function(ct, position){
50656 if(this.el){ // from markup
50657 this.el = Roo.get(this.el);
50658 }else { // generate
50659 var cfg = this.getAutoCreate();
50660 this.el = ct.createChild(cfg, position);
50663 this.el.applyStyles(this.style);
50665 if(this.labelAlign){
50666 this.el.addClass('x-form-label-'+this.labelAlign);
50668 if(this.hideLabels){
50669 this.labelStyle = "display:none";
50670 this.elementStyle = "padding-left:0;";
50672 if(typeof this.labelWidth == 'number'){
50673 this.labelStyle = "width:"+this.labelWidth+"px;";
50674 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
50676 if(this.labelAlign == 'top'){
50677 this.labelStyle = "width:auto;";
50678 this.elementStyle = "padding-left:0;";
50681 var stack = this.stack;
50682 var slen = stack.length;
50684 if(!this.fieldTpl){
50685 var t = new Roo.Template(
50686 '<div class="x-form-item {5}">',
50687 '<label for="{0}" style="{2}">{1}{4}</label>',
50688 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
50690 '</div><div class="x-form-clear-left"></div>'
50692 t.disableFormats = true;
50694 Roo.form.Layout.prototype.fieldTpl = t;
50696 for(var i = 0; i < slen; i++) {
50697 if(stack[i].isFormField){
50698 this.renderField(stack[i]);
50700 this.renderComponent(stack[i]);
50705 this.el.createChild({cls:'x-form-clear'});
50710 renderField : function(f){
50711 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
50714 f.labelStyle||this.labelStyle||'', //2
50715 this.elementStyle||'', //3
50716 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
50717 f.itemCls||this.itemCls||'' //5
50718 ], true).getPrevSibling());
50722 renderComponent : function(c){
50723 c.render(c.isLayout ? this.el : this.el.createChild());
50726 * Adds a object form elements (using the xtype property as the factory method.)
50727 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
50728 * @param {Object} config
50730 addxtype : function(o)
50732 // create the lement.
50733 o.form = this.form;
50734 var fe = Roo.factory(o, Roo.form);
50735 this.form.allItems.push(fe);
50736 this.stack.push(fe);
50738 if (fe.isFormField) {
50739 this.form.items.add(fe);
50747 * @class Roo.form.Column
50748 * @extends Roo.form.Layout
50749 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
50751 * @param {Object} config Configuration options
50753 Roo.form.Column = function(config){
50754 Roo.form.Column.superclass.constructor.call(this, config);
50757 Roo.extend(Roo.form.Column, Roo.form.Layout, {
50759 * @cfg {Number/String} width
50760 * The fixed width of the column in pixels or CSS value (defaults to "auto")
50763 * @cfg {String/Object} autoCreate
50764 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
50768 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
50771 onRender : function(ct, position){
50772 Roo.form.Column.superclass.onRender.call(this, ct, position);
50774 this.el.setWidth(this.width);
50781 * @class Roo.form.Row
50782 * @extends Roo.form.Layout
50783 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
50784 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
50786 * @param {Object} config Configuration options
50790 Roo.form.Row = function(config){
50791 Roo.form.Row.superclass.constructor.call(this, config);
50794 Roo.extend(Roo.form.Row, Roo.form.Layout, {
50796 * @cfg {Number/String} width
50797 * The fixed width of the column in pixels or CSS value (defaults to "auto")
50800 * @cfg {Number/String} height
50801 * The fixed height of the column in pixels or CSS value (defaults to "auto")
50803 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
50807 onRender : function(ct, position){
50808 //console.log('row render');
50810 var t = new Roo.Template(
50811 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
50812 '<label for="{0}" style="{2}">{1}{4}</label>',
50813 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
50817 t.disableFormats = true;
50819 Roo.form.Layout.prototype.rowTpl = t;
50821 this.fieldTpl = this.rowTpl;
50823 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
50824 var labelWidth = 100;
50826 if ((this.labelAlign != 'top')) {
50827 if (typeof this.labelWidth == 'number') {
50828 labelWidth = this.labelWidth
50830 this.padWidth = 20 + labelWidth;
50834 Roo.form.Column.superclass.onRender.call(this, ct, position);
50836 this.el.setWidth(this.width);
50839 this.el.setHeight(this.height);
50844 renderField : function(f){
50845 f.fieldEl = this.fieldTpl.append(this.el, [
50846 f.id, f.fieldLabel,
50847 f.labelStyle||this.labelStyle||'',
50848 this.elementStyle||'',
50849 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
50850 f.itemCls||this.itemCls||'',
50851 f.width ? f.width + this.padWidth : 160 + this.padWidth
50858 * @class Roo.form.FieldSet
50859 * @extends Roo.form.Layout
50860 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
50861 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
50863 * @param {Object} config Configuration options
50865 Roo.form.FieldSet = function(config){
50866 Roo.form.FieldSet.superclass.constructor.call(this, config);
50869 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
50871 * @cfg {String} legend
50872 * The text to display as the legend for the FieldSet (defaults to '')
50875 * @cfg {String/Object} autoCreate
50876 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
50880 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
50883 onRender : function(ct, position){
50884 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
50886 this.setLegend(this.legend);
50891 setLegend : function(text){
50893 this.el.child('legend').update(text);
50898 * Ext JS Library 1.1.1
50899 * Copyright(c) 2006-2007, Ext JS, LLC.
50901 * Originally Released Under LGPL - original licence link has changed is not relivant.
50904 * <script type="text/javascript">
50907 * @class Roo.form.VTypes
50908 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
50911 Roo.form.VTypes = function(){
50912 // closure these in so they are only created once.
50913 var alpha = /^[a-zA-Z_]+$/;
50914 var alphanum = /^[a-zA-Z0-9_]+$/;
50915 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
50916 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
50918 // All these messages and functions are configurable
50921 * The function used to validate email addresses
50922 * @param {String} value The email address
50924 'email' : function(v){
50925 return email.test(v);
50928 * The error text to display when the email validation function returns false
50931 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
50933 * The keystroke filter mask to be applied on email input
50936 'emailMask' : /[a-z0-9_\.\-@]/i,
50939 * The function used to validate URLs
50940 * @param {String} value The URL
50942 'url' : function(v){
50943 return url.test(v);
50946 * The error text to display when the url validation function returns false
50949 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
50952 * The function used to validate alpha values
50953 * @param {String} value The value
50955 'alpha' : function(v){
50956 return alpha.test(v);
50959 * The error text to display when the alpha validation function returns false
50962 'alphaText' : 'This field should only contain letters and _',
50964 * The keystroke filter mask to be applied on alpha input
50967 'alphaMask' : /[a-z_]/i,
50970 * The function used to validate alphanumeric values
50971 * @param {String} value The value
50973 'alphanum' : function(v){
50974 return alphanum.test(v);
50977 * The error text to display when the alphanumeric validation function returns false
50980 'alphanumText' : 'This field should only contain letters, numbers and _',
50982 * The keystroke filter mask to be applied on alphanumeric input
50985 'alphanumMask' : /[a-z0-9_]/i
50987 }();//<script type="text/javascript">
50990 * @class Roo.form.FCKeditor
50991 * @extends Roo.form.TextArea
50992 * Wrapper around the FCKEditor http://www.fckeditor.net
50994 * Creates a new FCKeditor
50995 * @param {Object} config Configuration options
50997 Roo.form.FCKeditor = function(config){
50998 Roo.form.FCKeditor.superclass.constructor.call(this, config);
51001 * @event editorinit
51002 * Fired when the editor is initialized - you can add extra handlers here..
51003 * @param {FCKeditor} this
51004 * @param {Object} the FCK object.
51011 Roo.form.FCKeditor.editors = { };
51012 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
51014 //defaultAutoCreate : {
51015 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
51019 * @cfg {Object} fck options - see fck manual for details.
51024 * @cfg {Object} fck toolbar set (Basic or Default)
51026 toolbarSet : 'Basic',
51028 * @cfg {Object} fck BasePath
51030 basePath : '/fckeditor/',
51038 onRender : function(ct, position)
51041 this.defaultAutoCreate = {
51043 style:"width:300px;height:60px;",
51044 autocomplete: "new-password"
51047 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
51050 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
51051 if(this.preventScrollbars){
51052 this.el.setStyle("overflow", "hidden");
51054 this.el.setHeight(this.growMin);
51057 //console.log('onrender' + this.getId() );
51058 Roo.form.FCKeditor.editors[this.getId()] = this;
51061 this.replaceTextarea() ;
51065 getEditor : function() {
51066 return this.fckEditor;
51069 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
51070 * @param {Mixed} value The value to set
51074 setValue : function(value)
51076 //console.log('setValue: ' + value);
51078 if(typeof(value) == 'undefined') { // not sure why this is happending...
51081 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
51083 //if(!this.el || !this.getEditor()) {
51084 // this.value = value;
51085 //this.setValue.defer(100,this,[value]);
51089 if(!this.getEditor()) {
51093 this.getEditor().SetData(value);
51100 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
51101 * @return {Mixed} value The field value
51103 getValue : function()
51106 if (this.frame && this.frame.dom.style.display == 'none') {
51107 return Roo.form.FCKeditor.superclass.getValue.call(this);
51110 if(!this.el || !this.getEditor()) {
51112 // this.getValue.defer(100,this);
51117 var value=this.getEditor().GetData();
51118 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
51119 return Roo.form.FCKeditor.superclass.getValue.call(this);
51125 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
51126 * @return {Mixed} value The field value
51128 getRawValue : function()
51130 if (this.frame && this.frame.dom.style.display == 'none') {
51131 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
51134 if(!this.el || !this.getEditor()) {
51135 //this.getRawValue.defer(100,this);
51142 var value=this.getEditor().GetData();
51143 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
51144 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
51148 setSize : function(w,h) {
51152 //if (this.frame && this.frame.dom.style.display == 'none') {
51153 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
51156 //if(!this.el || !this.getEditor()) {
51157 // this.setSize.defer(100,this, [w,h]);
51163 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
51165 this.frame.dom.setAttribute('width', w);
51166 this.frame.dom.setAttribute('height', h);
51167 this.frame.setSize(w,h);
51171 toggleSourceEdit : function(value) {
51175 this.el.dom.style.display = value ? '' : 'none';
51176 this.frame.dom.style.display = value ? 'none' : '';
51181 focus: function(tag)
51183 if (this.frame.dom.style.display == 'none') {
51184 return Roo.form.FCKeditor.superclass.focus.call(this);
51186 if(!this.el || !this.getEditor()) {
51187 this.focus.defer(100,this, [tag]);
51194 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
51195 this.getEditor().Focus();
51197 if (!this.getEditor().Selection.GetSelection()) {
51198 this.focus.defer(100,this, [tag]);
51203 var r = this.getEditor().EditorDocument.createRange();
51204 r.setStart(tgs[0],0);
51205 r.setEnd(tgs[0],0);
51206 this.getEditor().Selection.GetSelection().removeAllRanges();
51207 this.getEditor().Selection.GetSelection().addRange(r);
51208 this.getEditor().Focus();
51215 replaceTextarea : function()
51217 if ( document.getElementById( this.getId() + '___Frame' ) ) {
51220 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
51222 // We must check the elements firstly using the Id and then the name.
51223 var oTextarea = document.getElementById( this.getId() );
51225 var colElementsByName = document.getElementsByName( this.getId() ) ;
51227 oTextarea.style.display = 'none' ;
51229 if ( oTextarea.tabIndex ) {
51230 this.TabIndex = oTextarea.tabIndex ;
51233 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
51234 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
51235 this.frame = Roo.get(this.getId() + '___Frame')
51238 _getConfigHtml : function()
51242 for ( var o in this.fckconfig ) {
51243 sConfig += sConfig.length > 0 ? '&' : '';
51244 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
51247 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
51251 _getIFrameHtml : function()
51253 var sFile = 'fckeditor.html' ;
51254 /* no idea what this is about..
51257 if ( (/fcksource=true/i).test( window.top.location.search ) )
51258 sFile = 'fckeditor.original.html' ;
51263 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
51264 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
51267 var html = '<iframe id="' + this.getId() +
51268 '___Frame" src="' + sLink +
51269 '" width="' + this.width +
51270 '" height="' + this.height + '"' +
51271 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
51272 ' frameborder="0" scrolling="no"></iframe>' ;
51277 _insertHtmlBefore : function( html, element )
51279 if ( element.insertAdjacentHTML ) {
51281 element.insertAdjacentHTML( 'beforeBegin', html ) ;
51283 var oRange = document.createRange() ;
51284 oRange.setStartBefore( element ) ;
51285 var oFragment = oRange.createContextualFragment( html );
51286 element.parentNode.insertBefore( oFragment, element ) ;
51299 //Roo.reg('fckeditor', Roo.form.FCKeditor);
51301 function FCKeditor_OnComplete(editorInstance){
51302 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
51303 f.fckEditor = editorInstance;
51304 //console.log("loaded");
51305 f.fireEvent('editorinit', f, editorInstance);
51325 //<script type="text/javascript">
51327 * @class Roo.form.GridField
51328 * @extends Roo.form.Field
51329 * Embed a grid (or editable grid into a form)
51332 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
51334 * xgrid.store = Roo.data.Store
51335 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
51336 * xgrid.store.reader = Roo.data.JsonReader
51340 * Creates a new GridField
51341 * @param {Object} config Configuration options
51343 Roo.form.GridField = function(config){
51344 Roo.form.GridField.superclass.constructor.call(this, config);
51348 Roo.extend(Roo.form.GridField, Roo.form.Field, {
51350 * @cfg {Number} width - used to restrict width of grid..
51354 * @cfg {Number} height - used to restrict height of grid..
51358 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
51364 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
51365 * {tag: "input", type: "checkbox", autocomplete: "off"})
51367 // defaultAutoCreate : { tag: 'div' },
51368 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
51370 * @cfg {String} addTitle Text to include for adding a title.
51374 onResize : function(){
51375 Roo.form.Field.superclass.onResize.apply(this, arguments);
51378 initEvents : function(){
51379 // Roo.form.Checkbox.superclass.initEvents.call(this);
51380 // has no events...
51385 getResizeEl : function(){
51389 getPositionEl : function(){
51394 onRender : function(ct, position){
51396 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
51397 var style = this.style;
51400 Roo.form.GridField.superclass.onRender.call(this, ct, position);
51401 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
51402 this.viewEl = this.wrap.createChild({ tag: 'div' });
51404 this.viewEl.applyStyles(style);
51407 this.viewEl.setWidth(this.width);
51410 this.viewEl.setHeight(this.height);
51412 //if(this.inputValue !== undefined){
51413 //this.setValue(this.value);
51416 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
51419 this.grid.render();
51420 this.grid.getDataSource().on('remove', this.refreshValue, this);
51421 this.grid.getDataSource().on('update', this.refreshValue, this);
51422 this.grid.on('afteredit', this.refreshValue, this);
51428 * Sets the value of the item.
51429 * @param {String} either an object or a string..
51431 setValue : function(v){
51433 v = v || []; // empty set..
51434 // this does not seem smart - it really only affects memoryproxy grids..
51435 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
51436 var ds = this.grid.getDataSource();
51437 // assumes a json reader..
51439 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
51440 ds.loadData( data);
51442 // clear selection so it does not get stale.
51443 if (this.grid.sm) {
51444 this.grid.sm.clearSelections();
51447 Roo.form.GridField.superclass.setValue.call(this, v);
51448 this.refreshValue();
51449 // should load data in the grid really....
51453 refreshValue: function() {
51455 this.grid.getDataSource().each(function(r) {
51458 this.el.dom.value = Roo.encode(val);
51466 * Ext JS Library 1.1.1
51467 * Copyright(c) 2006-2007, Ext JS, LLC.
51469 * Originally Released Under LGPL - original licence link has changed is not relivant.
51472 * <script type="text/javascript">
51475 * @class Roo.form.DisplayField
51476 * @extends Roo.form.Field
51477 * A generic Field to display non-editable data.
51478 * @cfg {Boolean} closable (true|false) default false
51480 * Creates a new Display Field item.
51481 * @param {Object} config Configuration options
51483 Roo.form.DisplayField = function(config){
51484 Roo.form.DisplayField.superclass.constructor.call(this, config);
51489 * Fires after the click the close btn
51490 * @param {Roo.form.DisplayField} this
51496 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
51497 inputType: 'hidden',
51503 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
51505 focusClass : undefined,
51507 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
51509 fieldClass: 'x-form-field',
51512 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
51514 valueRenderer: undefined,
51518 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
51519 * {tag: "input", type: "checkbox", autocomplete: "off"})
51522 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
51526 onResize : function(){
51527 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
51531 initEvents : function(){
51532 // Roo.form.Checkbox.superclass.initEvents.call(this);
51533 // has no events...
51536 this.closeEl.on('click', this.onClose, this);
51542 getResizeEl : function(){
51546 getPositionEl : function(){
51551 onRender : function(ct, position){
51553 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
51554 //if(this.inputValue !== undefined){
51555 this.wrap = this.el.wrap();
51557 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
51560 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
51563 if (this.bodyStyle) {
51564 this.viewEl.applyStyles(this.bodyStyle);
51566 //this.viewEl.setStyle('padding', '2px');
51568 this.setValue(this.value);
51573 initValue : Roo.emptyFn,
51578 onClick : function(){
51583 * Sets the checked state of the checkbox.
51584 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
51586 setValue : function(v){
51588 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
51589 // this might be called before we have a dom element..
51590 if (!this.viewEl) {
51593 this.viewEl.dom.innerHTML = html;
51594 Roo.form.DisplayField.superclass.setValue.call(this, v);
51598 onClose : function(e)
51600 e.preventDefault();
51602 this.fireEvent('close', this);
51611 * @class Roo.form.DayPicker
51612 * @extends Roo.form.Field
51613 * A Day picker show [M] [T] [W] ....
51615 * Creates a new Day Picker
51616 * @param {Object} config Configuration options
51618 Roo.form.DayPicker= function(config){
51619 Roo.form.DayPicker.superclass.constructor.call(this, config);
51623 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
51625 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
51627 focusClass : undefined,
51629 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
51631 fieldClass: "x-form-field",
51634 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
51635 * {tag: "input", type: "checkbox", autocomplete: "off"})
51637 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
51640 actionMode : 'viewEl',
51644 inputType : 'hidden',
51647 inputElement: false, // real input element?
51648 basedOn: false, // ????
51650 isFormField: true, // not sure where this is needed!!!!
51652 onResize : function(){
51653 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
51654 if(!this.boxLabel){
51655 this.el.alignTo(this.wrap, 'c-c');
51659 initEvents : function(){
51660 Roo.form.Checkbox.superclass.initEvents.call(this);
51661 this.el.on("click", this.onClick, this);
51662 this.el.on("change", this.onClick, this);
51666 getResizeEl : function(){
51670 getPositionEl : function(){
51676 onRender : function(ct, position){
51677 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
51679 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
51681 var r1 = '<table><tr>';
51682 var r2 = '<tr class="x-form-daypick-icons">';
51683 for (var i=0; i < 7; i++) {
51684 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
51685 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
51688 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
51689 viewEl.select('img').on('click', this.onClick, this);
51690 this.viewEl = viewEl;
51693 // this will not work on Chrome!!!
51694 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
51695 this.el.on('propertychange', this.setFromHidden, this); //ie
51703 initValue : Roo.emptyFn,
51706 * Returns the checked state of the checkbox.
51707 * @return {Boolean} True if checked, else false
51709 getValue : function(){
51710 return this.el.dom.value;
51715 onClick : function(e){
51716 //this.setChecked(!this.checked);
51717 Roo.get(e.target).toggleClass('x-menu-item-checked');
51718 this.refreshValue();
51719 //if(this.el.dom.checked != this.checked){
51720 // this.setValue(this.el.dom.checked);
51725 refreshValue : function()
51728 this.viewEl.select('img',true).each(function(e,i,n) {
51729 val += e.is(".x-menu-item-checked") ? String(n) : '';
51731 this.setValue(val, true);
51735 * Sets the checked state of the checkbox.
51736 * On is always based on a string comparison between inputValue and the param.
51737 * @param {Boolean/String} value - the value to set
51738 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
51740 setValue : function(v,suppressEvent){
51741 if (!this.el.dom) {
51744 var old = this.el.dom.value ;
51745 this.el.dom.value = v;
51746 if (suppressEvent) {
51750 // update display..
51751 this.viewEl.select('img',true).each(function(e,i,n) {
51753 var on = e.is(".x-menu-item-checked");
51754 var newv = v.indexOf(String(n)) > -1;
51756 e.toggleClass('x-menu-item-checked');
51762 this.fireEvent('change', this, v, old);
51767 // handle setting of hidden value by some other method!!?!?
51768 setFromHidden: function()
51773 //console.log("SET FROM HIDDEN");
51774 //alert('setFrom hidden');
51775 this.setValue(this.el.dom.value);
51778 onDestroy : function()
51781 Roo.get(this.viewEl).remove();
51784 Roo.form.DayPicker.superclass.onDestroy.call(this);
51788 * RooJS Library 1.1.1
51789 * Copyright(c) 2008-2011 Alan Knowles
51796 * @class Roo.form.ComboCheck
51797 * @extends Roo.form.ComboBox
51798 * A combobox for multiple select items.
51800 * FIXME - could do with a reset button..
51803 * Create a new ComboCheck
51804 * @param {Object} config Configuration options
51806 Roo.form.ComboCheck = function(config){
51807 Roo.form.ComboCheck.superclass.constructor.call(this, config);
51808 // should verify some data...
51810 // hiddenName = required..
51811 // displayField = required
51812 // valudField == required
51813 var req= [ 'hiddenName', 'displayField', 'valueField' ];
51815 Roo.each(req, function(e) {
51816 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
51817 throw "Roo.form.ComboCheck : missing value for: " + e;
51824 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
51829 selectedClass: 'x-menu-item-checked',
51832 onRender : function(ct, position){
51838 var cls = 'x-combo-list';
51841 this.tpl = new Roo.Template({
51842 html : '<div class="'+cls+'-item x-menu-check-item">' +
51843 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
51844 '<span>{' + this.displayField + '}</span>' +
51851 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
51852 this.view.singleSelect = false;
51853 this.view.multiSelect = true;
51854 this.view.toggleSelect = true;
51855 this.pageTb.add(new Roo.Toolbar.Fill(), {
51858 handler: function()
51865 onViewOver : function(e, t){
51871 onViewClick : function(doFocus,index){
51875 select: function () {
51876 //Roo.log("SELECT CALLED");
51879 selectByValue : function(xv, scrollIntoView){
51880 var ar = this.getValueArray();
51883 Roo.each(ar, function(v) {
51884 if(v === undefined || v === null){
51887 var r = this.findRecord(this.valueField, v);
51889 sels.push(this.store.indexOf(r))
51893 this.view.select(sels);
51899 onSelect : function(record, index){
51900 // Roo.log("onselect Called");
51901 // this is only called by the clear button now..
51902 this.view.clearSelections();
51903 this.setValue('[]');
51904 if (this.value != this.valueBefore) {
51905 this.fireEvent('change', this, this.value, this.valueBefore);
51906 this.valueBefore = this.value;
51909 getValueArray : function()
51914 //Roo.log(this.value);
51915 if (typeof(this.value) == 'undefined') {
51918 var ar = Roo.decode(this.value);
51919 return ar instanceof Array ? ar : []; //?? valid?
51922 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
51927 expand : function ()
51930 Roo.form.ComboCheck.superclass.expand.call(this);
51931 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
51932 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
51937 collapse : function(){
51938 Roo.form.ComboCheck.superclass.collapse.call(this);
51939 var sl = this.view.getSelectedIndexes();
51940 var st = this.store;
51944 Roo.each(sl, function(i) {
51946 nv.push(r.get(this.valueField));
51948 this.setValue(Roo.encode(nv));
51949 if (this.value != this.valueBefore) {
51951 this.fireEvent('change', this, this.value, this.valueBefore);
51952 this.valueBefore = this.value;
51957 setValue : function(v){
51961 var vals = this.getValueArray();
51963 Roo.each(vals, function(k) {
51964 var r = this.findRecord(this.valueField, k);
51966 tv.push(r.data[this.displayField]);
51967 }else if(this.valueNotFoundText !== undefined){
51968 tv.push( this.valueNotFoundText );
51973 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
51974 this.hiddenField.value = v;
51980 * Ext JS Library 1.1.1
51981 * Copyright(c) 2006-2007, Ext JS, LLC.
51983 * Originally Released Under LGPL - original licence link has changed is not relivant.
51986 * <script type="text/javascript">
51990 * @class Roo.form.Signature
51991 * @extends Roo.form.Field
51995 * @param {Object} config Configuration options
51998 Roo.form.Signature = function(config){
51999 Roo.form.Signature.superclass.constructor.call(this, config);
52001 this.addEvents({// not in used??
52004 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
52005 * @param {Roo.form.Signature} combo This combo box
52010 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
52011 * @param {Roo.form.ComboBox} combo This combo box
52012 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
52018 Roo.extend(Roo.form.Signature, Roo.form.Field, {
52020 * @cfg {Object} labels Label to use when rendering a form.
52024 * confirm : "Confirm"
52029 confirm : "Confirm"
52032 * @cfg {Number} width The signature panel width (defaults to 300)
52036 * @cfg {Number} height The signature panel height (defaults to 100)
52040 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
52042 allowBlank : false,
52045 // {Object} signPanel The signature SVG panel element (defaults to {})
52047 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
52048 isMouseDown : false,
52049 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
52050 isConfirmed : false,
52051 // {String} signatureTmp SVG mapping string (defaults to empty string)
52055 defaultAutoCreate : { // modified by initCompnoent..
52061 onRender : function(ct, position){
52063 Roo.form.Signature.superclass.onRender.call(this, ct, position);
52065 this.wrap = this.el.wrap({
52066 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
52069 this.createToolbar(this);
52070 this.signPanel = this.wrap.createChild({
52072 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
52076 this.svgID = Roo.id();
52077 this.svgEl = this.signPanel.createChild({
52078 xmlns : 'http://www.w3.org/2000/svg',
52080 id : this.svgID + "-svg",
52082 height: this.height,
52083 viewBox: '0 0 '+this.width+' '+this.height,
52087 id: this.svgID + "-svg-r",
52089 height: this.height,
52094 id: this.svgID + "-svg-l",
52096 y1: (this.height*0.8), // start set the line in 80% of height
52097 x2: this.width, // end
52098 y2: (this.height*0.8), // end set the line in 80% of height
52100 'stroke-width': "1",
52101 'stroke-dasharray': "3",
52102 'shape-rendering': "crispEdges",
52103 'pointer-events': "none"
52107 id: this.svgID + "-svg-p",
52109 'stroke-width': "3",
52111 'pointer-events': 'none'
52116 this.svgBox = this.svgEl.dom.getScreenCTM();
52118 createSVG : function(){
52119 var svg = this.signPanel;
52120 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
52123 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
52124 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
52125 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
52126 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
52127 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
52128 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
52129 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
52132 isTouchEvent : function(e){
52133 return e.type.match(/^touch/);
52135 getCoords : function (e) {
52136 var pt = this.svgEl.dom.createSVGPoint();
52139 if (this.isTouchEvent(e)) {
52140 pt.x = e.targetTouches[0].clientX;
52141 pt.y = e.targetTouches[0].clientY;
52143 var a = this.svgEl.dom.getScreenCTM();
52144 var b = a.inverse();
52145 var mx = pt.matrixTransform(b);
52146 return mx.x + ',' + mx.y;
52148 //mouse event headler
52149 down : function (e) {
52150 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
52151 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
52153 this.isMouseDown = true;
52155 e.preventDefault();
52157 move : function (e) {
52158 if (this.isMouseDown) {
52159 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
52160 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
52163 e.preventDefault();
52165 up : function (e) {
52166 this.isMouseDown = false;
52167 var sp = this.signatureTmp.split(' ');
52170 if(!sp[sp.length-2].match(/^L/)){
52174 this.signatureTmp = sp.join(" ");
52177 if(this.getValue() != this.signatureTmp){
52178 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
52179 this.isConfirmed = false;
52181 e.preventDefault();
52185 * Protected method that will not generally be called directly. It
52186 * is called when the editor creates its toolbar. Override this method if you need to
52187 * add custom toolbar buttons.
52188 * @param {HtmlEditor} editor
52190 createToolbar : function(editor){
52191 function btn(id, toggle, handler){
52192 var xid = fid + '-'+ id ;
52196 cls : 'x-btn-icon x-edit-'+id,
52197 enableToggle:toggle !== false,
52198 scope: editor, // was editor...
52199 handler:handler||editor.relayBtnCmd,
52200 clickEvent:'mousedown',
52201 tooltip: etb.buttonTips[id] || undefined, ///tips ???
52207 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
52211 cls : ' x-signature-btn x-signature-'+id,
52212 scope: editor, // was editor...
52213 handler: this.reset,
52214 clickEvent:'mousedown',
52215 text: this.labels.clear
52222 cls : ' x-signature-btn x-signature-'+id,
52223 scope: editor, // was editor...
52224 handler: this.confirmHandler,
52225 clickEvent:'mousedown',
52226 text: this.labels.confirm
52233 * when user is clicked confirm then show this image.....
52235 * @return {String} Image Data URI
52237 getImageDataURI : function(){
52238 var svg = this.svgEl.dom.parentNode.innerHTML;
52239 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
52244 * @return {Boolean} this.isConfirmed
52246 getConfirmed : function(){
52247 return this.isConfirmed;
52251 * @return {Number} this.width
52253 getWidth : function(){
52258 * @return {Number} this.height
52260 getHeight : function(){
52261 return this.height;
52264 getSignature : function(){
52265 return this.signatureTmp;
52268 reset : function(){
52269 this.signatureTmp = '';
52270 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
52271 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
52272 this.isConfirmed = false;
52273 Roo.form.Signature.superclass.reset.call(this);
52275 setSignature : function(s){
52276 this.signatureTmp = s;
52277 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
52278 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
52280 this.isConfirmed = false;
52281 Roo.form.Signature.superclass.reset.call(this);
52284 // Roo.log(this.signPanel.dom.contentWindow.up())
52287 setConfirmed : function(){
52291 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
52294 confirmHandler : function(){
52295 if(!this.getSignature()){
52299 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
52300 this.setValue(this.getSignature());
52301 this.isConfirmed = true;
52303 this.fireEvent('confirm', this);
52306 // Subclasses should provide the validation implementation by overriding this
52307 validateValue : function(value){
52308 if(this.allowBlank){
52312 if(this.isConfirmed){
52319 * Ext JS Library 1.1.1
52320 * Copyright(c) 2006-2007, Ext JS, LLC.
52322 * Originally Released Under LGPL - original licence link has changed is not relivant.
52325 * <script type="text/javascript">
52330 * @class Roo.form.ComboBox
52331 * @extends Roo.form.TriggerField
52332 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
52334 * Create a new ComboBox.
52335 * @param {Object} config Configuration options
52337 Roo.form.Select = function(config){
52338 Roo.form.Select.superclass.constructor.call(this, config);
52342 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
52344 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
52347 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
52348 * rendering into an Roo.Editor, defaults to false)
52351 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
52352 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
52355 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
52358 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
52359 * the dropdown list (defaults to undefined, with no header element)
52363 * @cfg {String/Roo.Template} tpl The template to use to render the output
52367 defaultAutoCreate : {tag: "select" },
52369 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
52371 listWidth: undefined,
52373 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
52374 * mode = 'remote' or 'text' if mode = 'local')
52376 displayField: undefined,
52378 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
52379 * mode = 'remote' or 'value' if mode = 'local').
52380 * Note: use of a valueField requires the user make a selection
52381 * in order for a value to be mapped.
52383 valueField: undefined,
52387 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
52388 * field's data value (defaults to the underlying DOM element's name)
52390 hiddenName: undefined,
52392 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
52396 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
52398 selectedClass: 'x-combo-selected',
52400 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
52401 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
52402 * which displays a downward arrow icon).
52404 triggerClass : 'x-form-arrow-trigger',
52406 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
52410 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
52411 * anchor positions (defaults to 'tl-bl')
52413 listAlign: 'tl-bl?',
52415 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
52419 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
52420 * query specified by the allQuery config option (defaults to 'query')
52422 triggerAction: 'query',
52424 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
52425 * (defaults to 4, does not apply if editable = false)
52429 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
52430 * delay (typeAheadDelay) if it matches a known value (defaults to false)
52434 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
52435 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
52439 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
52440 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
52444 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
52445 * when editable = true (defaults to false)
52447 selectOnFocus:false,
52449 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
52451 queryParam: 'query',
52453 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
52454 * when mode = 'remote' (defaults to 'Loading...')
52456 loadingText: 'Loading...',
52458 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
52462 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
52466 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
52467 * traditional select (defaults to true)
52471 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
52475 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
52479 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
52480 * listWidth has a higher value)
52484 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
52485 * allow the user to set arbitrary text into the field (defaults to false)
52487 forceSelection:false,
52489 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
52490 * if typeAhead = true (defaults to 250)
52492 typeAheadDelay : 250,
52494 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
52495 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
52497 valueNotFoundText : undefined,
52500 * @cfg {String} defaultValue The value displayed after loading the store.
52505 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
52507 blockFocus : false,
52510 * @cfg {Boolean} disableClear Disable showing of clear button.
52512 disableClear : false,
52514 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
52516 alwaysQuery : false,
52522 // element that contains real text value.. (when hidden is used..)
52525 onRender : function(ct, position){
52526 Roo.form.Field.prototype.onRender.call(this, ct, position);
52529 this.store.on('beforeload', this.onBeforeLoad, this);
52530 this.store.on('load', this.onLoad, this);
52531 this.store.on('loadexception', this.onLoadException, this);
52532 this.store.load({});
52540 initEvents : function(){
52541 //Roo.form.ComboBox.superclass.initEvents.call(this);
52545 onDestroy : function(){
52548 this.store.un('beforeload', this.onBeforeLoad, this);
52549 this.store.un('load', this.onLoad, this);
52550 this.store.un('loadexception', this.onLoadException, this);
52552 //Roo.form.ComboBox.superclass.onDestroy.call(this);
52556 fireKey : function(e){
52557 if(e.isNavKeyPress() && !this.list.isVisible()){
52558 this.fireEvent("specialkey", this, e);
52563 onResize: function(w, h){
52571 * Allow or prevent the user from directly editing the field text. If false is passed,
52572 * the user will only be able to select from the items defined in the dropdown list. This method
52573 * is the runtime equivalent of setting the 'editable' config option at config time.
52574 * @param {Boolean} value True to allow the user to directly edit the field text
52576 setEditable : function(value){
52581 onBeforeLoad : function(){
52583 Roo.log("Select before load");
52586 this.innerList.update(this.loadingText ?
52587 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
52588 //this.restrictHeight();
52589 this.selectedIndex = -1;
52593 onLoad : function(){
52596 var dom = this.el.dom;
52597 dom.innerHTML = '';
52598 var od = dom.ownerDocument;
52600 if (this.emptyText) {
52601 var op = od.createElement('option');
52602 op.setAttribute('value', '');
52603 op.innerHTML = String.format('{0}', this.emptyText);
52604 dom.appendChild(op);
52606 if(this.store.getCount() > 0){
52608 var vf = this.valueField;
52609 var df = this.displayField;
52610 this.store.data.each(function(r) {
52611 // which colmsn to use... testing - cdoe / title..
52612 var op = od.createElement('option');
52613 op.setAttribute('value', r.data[vf]);
52614 op.innerHTML = String.format('{0}', r.data[df]);
52615 dom.appendChild(op);
52617 if (typeof(this.defaultValue != 'undefined')) {
52618 this.setValue(this.defaultValue);
52623 //this.onEmptyResults();
52628 onLoadException : function()
52630 dom.innerHTML = '';
52632 Roo.log("Select on load exception");
52636 Roo.log(this.store.reader.jsonData);
52637 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
52638 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
52644 onTypeAhead : function(){
52649 onSelect : function(record, index){
52650 Roo.log('on select?');
52652 if(this.fireEvent('beforeselect', this, record, index) !== false){
52653 this.setFromData(index > -1 ? record.data : false);
52655 this.fireEvent('select', this, record, index);
52660 * Returns the currently selected field value or empty string if no value is set.
52661 * @return {String} value The selected value
52663 getValue : function(){
52664 var dom = this.el.dom;
52665 this.value = dom.options[dom.selectedIndex].value;
52671 * Clears any text/value currently set in the field
52673 clearValue : function(){
52675 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
52680 * Sets the specified value into the field. If the value finds a match, the corresponding record text
52681 * will be displayed in the field. If the value does not match the data value of an existing item,
52682 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
52683 * Otherwise the field will be blank (although the value will still be set).
52684 * @param {String} value The value to match
52686 setValue : function(v){
52687 var d = this.el.dom;
52688 for (var i =0; i < d.options.length;i++) {
52689 if (v == d.options[i].value) {
52690 d.selectedIndex = i;
52698 * @property {Object} the last set data for the element
52703 * Sets the value of the field based on a object which is related to the record format for the store.
52704 * @param {Object} value the value to set as. or false on reset?
52706 setFromData : function(o){
52707 Roo.log('setfrom data?');
52713 reset : function(){
52717 findRecord : function(prop, value){
52722 if(this.store.getCount() > 0){
52723 this.store.each(function(r){
52724 if(r.data[prop] == value){
52734 getName: function()
52736 // returns hidden if it's set..
52737 if (!this.rendered) {return ''};
52738 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
52746 onEmptyResults : function(){
52747 Roo.log('empty results');
52752 * Returns true if the dropdown list is expanded, else false.
52754 isExpanded : function(){
52759 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
52760 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
52761 * @param {String} value The data value of the item to select
52762 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
52763 * selected item if it is not currently in view (defaults to true)
52764 * @return {Boolean} True if the value matched an item in the list, else false
52766 selectByValue : function(v, scrollIntoView){
52767 Roo.log('select By Value');
52770 if(v !== undefined && v !== null){
52771 var r = this.findRecord(this.valueField || this.displayField, v);
52773 this.select(this.store.indexOf(r), scrollIntoView);
52781 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
52782 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
52783 * @param {Number} index The zero-based index of the list item to select
52784 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
52785 * selected item if it is not currently in view (defaults to true)
52787 select : function(index, scrollIntoView){
52788 Roo.log('select ');
52791 this.selectedIndex = index;
52792 this.view.select(index);
52793 if(scrollIntoView !== false){
52794 var el = this.view.getNode(index);
52796 this.innerList.scrollChildIntoView(el, false);
52804 validateBlur : function(){
52811 initQuery : function(){
52812 this.doQuery(this.getRawValue());
52816 doForce : function(){
52817 if(this.el.dom.value.length > 0){
52818 this.el.dom.value =
52819 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
52825 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
52826 * query allowing the query action to be canceled if needed.
52827 * @param {String} query The SQL query to execute
52828 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
52829 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
52830 * saved in the current store (defaults to false)
52832 doQuery : function(q, forceAll){
52834 Roo.log('doQuery?');
52835 if(q === undefined || q === null){
52840 forceAll: forceAll,
52844 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
52848 forceAll = qe.forceAll;
52849 if(forceAll === true || (q.length >= this.minChars)){
52850 if(this.lastQuery != q || this.alwaysQuery){
52851 this.lastQuery = q;
52852 if(this.mode == 'local'){
52853 this.selectedIndex = -1;
52855 this.store.clearFilter();
52857 this.store.filter(this.displayField, q);
52861 this.store.baseParams[this.queryParam] = q;
52863 params: this.getParams(q)
52868 this.selectedIndex = -1;
52875 getParams : function(q){
52877 //p[this.queryParam] = q;
52880 p.limit = this.pageSize;
52886 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
52888 collapse : function(){
52893 collapseIf : function(e){
52898 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
52900 expand : function(){
52908 * @cfg {Boolean} grow
52912 * @cfg {Number} growMin
52916 * @cfg {Number} growMax
52924 setWidth : function()
52928 getResizeEl : function(){
52931 });//<script type="text/javasscript">
52935 * @class Roo.DDView
52936 * A DnD enabled version of Roo.View.
52937 * @param {Element/String} container The Element in which to create the View.
52938 * @param {String} tpl The template string used to create the markup for each element of the View
52939 * @param {Object} config The configuration properties. These include all the config options of
52940 * {@link Roo.View} plus some specific to this class.<br>
52942 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
52943 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
52945 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
52946 .x-view-drag-insert-above {
52947 border-top:1px dotted #3366cc;
52949 .x-view-drag-insert-below {
52950 border-bottom:1px dotted #3366cc;
52956 Roo.DDView = function(container, tpl, config) {
52957 Roo.DDView.superclass.constructor.apply(this, arguments);
52958 this.getEl().setStyle("outline", "0px none");
52959 this.getEl().unselectable();
52960 if (this.dragGroup) {
52961 this.setDraggable(this.dragGroup.split(","));
52963 if (this.dropGroup) {
52964 this.setDroppable(this.dropGroup.split(","));
52966 if (this.deletable) {
52967 this.setDeletable();
52969 this.isDirtyFlag = false;
52975 Roo.extend(Roo.DDView, Roo.View, {
52976 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
52977 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
52978 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
52979 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
52983 reset: Roo.emptyFn,
52985 clearInvalid: Roo.form.Field.prototype.clearInvalid,
52987 validate: function() {
52991 destroy: function() {
52992 this.purgeListeners();
52993 this.getEl.removeAllListeners();
52994 this.getEl().remove();
52995 if (this.dragZone) {
52996 if (this.dragZone.destroy) {
52997 this.dragZone.destroy();
53000 if (this.dropZone) {
53001 if (this.dropZone.destroy) {
53002 this.dropZone.destroy();
53007 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
53008 getName: function() {
53012 /** Loads the View from a JSON string representing the Records to put into the Store. */
53013 setValue: function(v) {
53015 throw "DDView.setValue(). DDView must be constructed with a valid Store";
53018 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
53019 this.store.proxy = new Roo.data.MemoryProxy(data);
53023 /** @return {String} a parenthesised list of the ids of the Records in the View. */
53024 getValue: function() {
53026 this.store.each(function(rec) {
53027 result += rec.id + ',';
53029 return result.substr(0, result.length - 1) + ')';
53032 getIds: function() {
53033 var i = 0, result = new Array(this.store.getCount());
53034 this.store.each(function(rec) {
53035 result[i++] = rec.id;
53040 isDirty: function() {
53041 return this.isDirtyFlag;
53045 * Part of the Roo.dd.DropZone interface. If no target node is found, the
53046 * whole Element becomes the target, and this causes the drop gesture to append.
53048 getTargetFromEvent : function(e) {
53049 var target = e.getTarget();
53050 while ((target !== null) && (target.parentNode != this.el.dom)) {
53051 target = target.parentNode;
53054 target = this.el.dom.lastChild || this.el.dom;
53060 * Create the drag data which consists of an object which has the property "ddel" as
53061 * the drag proxy element.
53063 getDragData : function(e) {
53064 var target = this.findItemFromChild(e.getTarget());
53066 this.handleSelection(e);
53067 var selNodes = this.getSelectedNodes();
53070 copy: this.copy || (this.allowCopy && e.ctrlKey),
53074 var selectedIndices = this.getSelectedIndexes();
53075 for (var i = 0; i < selectedIndices.length; i++) {
53076 dragData.records.push(this.store.getAt(selectedIndices[i]));
53078 if (selNodes.length == 1) {
53079 dragData.ddel = target.cloneNode(true); // the div element
53081 var div = document.createElement('div'); // create the multi element drag "ghost"
53082 div.className = 'multi-proxy';
53083 for (var i = 0, len = selNodes.length; i < len; i++) {
53084 div.appendChild(selNodes[i].cloneNode(true));
53086 dragData.ddel = div;
53088 //console.log(dragData)
53089 //console.log(dragData.ddel.innerHTML)
53092 //console.log('nodragData')
53096 /** Specify to which ddGroup items in this DDView may be dragged. */
53097 setDraggable: function(ddGroup) {
53098 if (ddGroup instanceof Array) {
53099 Roo.each(ddGroup, this.setDraggable, this);
53102 if (this.dragZone) {
53103 this.dragZone.addToGroup(ddGroup);
53105 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
53106 containerScroll: true,
53110 // Draggability implies selection. DragZone's mousedown selects the element.
53111 if (!this.multiSelect) { this.singleSelect = true; }
53113 // Wire the DragZone's handlers up to methods in *this*
53114 this.dragZone.getDragData = this.getDragData.createDelegate(this);
53118 /** Specify from which ddGroup this DDView accepts drops. */
53119 setDroppable: function(ddGroup) {
53120 if (ddGroup instanceof Array) {
53121 Roo.each(ddGroup, this.setDroppable, this);
53124 if (this.dropZone) {
53125 this.dropZone.addToGroup(ddGroup);
53127 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
53128 containerScroll: true,
53132 // Wire the DropZone's handlers up to methods in *this*
53133 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
53134 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
53135 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
53136 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
53137 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
53141 /** Decide whether to drop above or below a View node. */
53142 getDropPoint : function(e, n, dd){
53143 if (n == this.el.dom) { return "above"; }
53144 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
53145 var c = t + (b - t) / 2;
53146 var y = Roo.lib.Event.getPageY(e);
53154 onNodeEnter : function(n, dd, e, data){
53158 onNodeOver : function(n, dd, e, data){
53159 var pt = this.getDropPoint(e, n, dd);
53160 // set the insert point style on the target node
53161 var dragElClass = this.dropNotAllowed;
53164 if (pt == "above"){
53165 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
53166 targetElClass = "x-view-drag-insert-above";
53168 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
53169 targetElClass = "x-view-drag-insert-below";
53171 if (this.lastInsertClass != targetElClass){
53172 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
53173 this.lastInsertClass = targetElClass;
53176 return dragElClass;
53179 onNodeOut : function(n, dd, e, data){
53180 this.removeDropIndicators(n);
53183 onNodeDrop : function(n, dd, e, data){
53184 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
53187 var pt = this.getDropPoint(e, n, dd);
53188 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
53189 if (pt == "below") { insertAt++; }
53190 for (var i = 0; i < data.records.length; i++) {
53191 var r = data.records[i];
53192 var dup = this.store.getById(r.id);
53193 if (dup && (dd != this.dragZone)) {
53194 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
53197 this.store.insert(insertAt++, r.copy());
53199 data.source.isDirtyFlag = true;
53201 this.store.insert(insertAt++, r);
53203 this.isDirtyFlag = true;
53206 this.dragZone.cachedTarget = null;
53210 removeDropIndicators : function(n){
53212 Roo.fly(n).removeClass([
53213 "x-view-drag-insert-above",
53214 "x-view-drag-insert-below"]);
53215 this.lastInsertClass = "_noclass";
53220 * Utility method. Add a delete option to the DDView's context menu.
53221 * @param {String} imageUrl The URL of the "delete" icon image.
53223 setDeletable: function(imageUrl) {
53224 if (!this.singleSelect && !this.multiSelect) {
53225 this.singleSelect = true;
53227 var c = this.getContextMenu();
53228 this.contextMenu.on("itemclick", function(item) {
53231 this.remove(this.getSelectedIndexes());
53235 this.contextMenu.add({
53242 /** Return the context menu for this DDView. */
53243 getContextMenu: function() {
53244 if (!this.contextMenu) {
53245 // Create the View's context menu
53246 this.contextMenu = new Roo.menu.Menu({
53247 id: this.id + "-contextmenu"
53249 this.el.on("contextmenu", this.showContextMenu, this);
53251 return this.contextMenu;
53254 disableContextMenu: function() {
53255 if (this.contextMenu) {
53256 this.el.un("contextmenu", this.showContextMenu, this);
53260 showContextMenu: function(e, item) {
53261 item = this.findItemFromChild(e.getTarget());
53264 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
53265 this.contextMenu.showAt(e.getXY());
53270 * Remove {@link Roo.data.Record}s at the specified indices.
53271 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
53273 remove: function(selectedIndices) {
53274 selectedIndices = [].concat(selectedIndices);
53275 for (var i = 0; i < selectedIndices.length; i++) {
53276 var rec = this.store.getAt(selectedIndices[i]);
53277 this.store.remove(rec);
53282 * Double click fires the event, but also, if this is draggable, and there is only one other
53283 * related DropZone, it transfers the selected node.
53285 onDblClick : function(e){
53286 var item = this.findItemFromChild(e.getTarget());
53288 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
53291 if (this.dragGroup) {
53292 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
53293 while (targets.indexOf(this.dropZone) > -1) {
53294 targets.remove(this.dropZone);
53296 if (targets.length == 1) {
53297 this.dragZone.cachedTarget = null;
53298 var el = Roo.get(targets[0].getEl());
53299 var box = el.getBox(true);
53300 targets[0].onNodeDrop(el.dom, {
53302 xy: [box.x, box.y + box.height - 1]
53303 }, null, this.getDragData(e));
53309 handleSelection: function(e) {
53310 this.dragZone.cachedTarget = null;
53311 var item = this.findItemFromChild(e.getTarget());
53313 this.clearSelections(true);
53316 if (item && (this.multiSelect || this.singleSelect)){
53317 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
53318 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
53319 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
53320 this.unselect(item);
53322 this.select(item, this.multiSelect && e.ctrlKey);
53323 this.lastSelection = item;
53328 onItemClick : function(item, index, e){
53329 if(this.fireEvent("beforeclick", this, index, item, e) === false){
53335 unselect : function(nodeInfo, suppressEvent){
53336 var node = this.getNode(nodeInfo);
53337 if(node && this.isSelected(node)){
53338 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
53339 Roo.fly(node).removeClass(this.selectedClass);
53340 this.selections.remove(node);
53341 if(!suppressEvent){
53342 this.fireEvent("selectionchange", this, this.selections);
53350 * Ext JS Library 1.1.1
53351 * Copyright(c) 2006-2007, Ext JS, LLC.
53353 * Originally Released Under LGPL - original licence link has changed is not relivant.
53356 * <script type="text/javascript">
53360 * @class Roo.LayoutManager
53361 * @extends Roo.util.Observable
53362 * Base class for layout managers.
53364 Roo.LayoutManager = function(container, config){
53365 Roo.LayoutManager.superclass.constructor.call(this);
53366 this.el = Roo.get(container);
53367 // ie scrollbar fix
53368 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
53369 document.body.scroll = "no";
53370 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
53371 this.el.position('relative');
53373 this.id = this.el.id;
53374 this.el.addClass("x-layout-container");
53375 /** false to disable window resize monitoring @type Boolean */
53376 this.monitorWindowResize = true;
53381 * Fires when a layout is performed.
53382 * @param {Roo.LayoutManager} this
53386 * @event regionresized
53387 * Fires when the user resizes a region.
53388 * @param {Roo.LayoutRegion} region The resized region
53389 * @param {Number} newSize The new size (width for east/west, height for north/south)
53391 "regionresized" : true,
53393 * @event regioncollapsed
53394 * Fires when a region is collapsed.
53395 * @param {Roo.LayoutRegion} region The collapsed region
53397 "regioncollapsed" : true,
53399 * @event regionexpanded
53400 * Fires when a region is expanded.
53401 * @param {Roo.LayoutRegion} region The expanded region
53403 "regionexpanded" : true
53405 this.updating = false;
53406 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
53409 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
53411 * Returns true if this layout is currently being updated
53412 * @return {Boolean}
53414 isUpdating : function(){
53415 return this.updating;
53419 * Suspend the LayoutManager from doing auto-layouts while
53420 * making multiple add or remove calls
53422 beginUpdate : function(){
53423 this.updating = true;
53427 * Restore auto-layouts and optionally disable the manager from performing a layout
53428 * @param {Boolean} noLayout true to disable a layout update
53430 endUpdate : function(noLayout){
53431 this.updating = false;
53437 layout: function(){
53441 onRegionResized : function(region, newSize){
53442 this.fireEvent("regionresized", region, newSize);
53446 onRegionCollapsed : function(region){
53447 this.fireEvent("regioncollapsed", region);
53450 onRegionExpanded : function(region){
53451 this.fireEvent("regionexpanded", region);
53455 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
53456 * performs box-model adjustments.
53457 * @return {Object} The size as an object {width: (the width), height: (the height)}
53459 getViewSize : function(){
53461 if(this.el.dom != document.body){
53462 size = this.el.getSize();
53464 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
53466 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
53467 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
53472 * Returns the Element this layout is bound to.
53473 * @return {Roo.Element}
53475 getEl : function(){
53480 * Returns the specified region.
53481 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
53482 * @return {Roo.LayoutRegion}
53484 getRegion : function(target){
53485 return this.regions[target.toLowerCase()];
53488 onWindowResize : function(){
53489 if(this.monitorWindowResize){
53495 * Ext JS Library 1.1.1
53496 * Copyright(c) 2006-2007, Ext JS, LLC.
53498 * Originally Released Under LGPL - original licence link has changed is not relivant.
53501 * <script type="text/javascript">
53504 * @class Roo.BorderLayout
53505 * @extends Roo.LayoutManager
53506 * @children Roo.ContentPanel
53507 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
53508 * please see: <br><br>
53509 * <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>
53510 * <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>
53513 var layout = new Roo.BorderLayout(document.body, {
53547 preferredTabWidth: 150
53552 var CP = Roo.ContentPanel;
53554 layout.beginUpdate();
53555 layout.add("north", new CP("north", "North"));
53556 layout.add("south", new CP("south", {title: "South", closable: true}));
53557 layout.add("west", new CP("west", {title: "West"}));
53558 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
53559 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
53560 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
53561 layout.getRegion("center").showPanel("center1");
53562 layout.endUpdate();
53565 <b>The container the layout is rendered into can be either the body element or any other element.
53566 If it is not the body element, the container needs to either be an absolute positioned element,
53567 or you will need to add "position:relative" to the css of the container. You will also need to specify
53568 the container size if it is not the body element.</b>
53571 * Create a new BorderLayout
53572 * @param {String/HTMLElement/Element} container The container this layout is bound to
53573 * @param {Object} config Configuration options
53575 Roo.BorderLayout = function(container, config){
53576 config = config || {};
53577 Roo.BorderLayout.superclass.constructor.call(this, container, config);
53578 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
53579 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
53580 var target = this.factory.validRegions[i];
53581 if(config[target]){
53582 this.addRegion(target, config[target]);
53587 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
53590 * @cfg {Roo.LayoutRegion} east
53593 * @cfg {Roo.LayoutRegion} west
53596 * @cfg {Roo.LayoutRegion} north
53599 * @cfg {Roo.LayoutRegion} south
53602 * @cfg {Roo.LayoutRegion} center
53605 * Creates and adds a new region if it doesn't already exist.
53606 * @param {String} target The target region key (north, south, east, west or center).
53607 * @param {Object} config The regions config object
53608 * @return {BorderLayoutRegion} The new region
53610 addRegion : function(target, config){
53611 if(!this.regions[target]){
53612 var r = this.factory.create(target, this, config);
53613 this.bindRegion(target, r);
53615 return this.regions[target];
53619 bindRegion : function(name, r){
53620 this.regions[name] = r;
53621 r.on("visibilitychange", this.layout, this);
53622 r.on("paneladded", this.layout, this);
53623 r.on("panelremoved", this.layout, this);
53624 r.on("invalidated", this.layout, this);
53625 r.on("resized", this.onRegionResized, this);
53626 r.on("collapsed", this.onRegionCollapsed, this);
53627 r.on("expanded", this.onRegionExpanded, this);
53631 * Performs a layout update.
53633 layout : function(){
53634 if(this.updating) {
53637 var size = this.getViewSize();
53638 var w = size.width;
53639 var h = size.height;
53644 //var x = 0, y = 0;
53646 var rs = this.regions;
53647 var north = rs["north"];
53648 var south = rs["south"];
53649 var west = rs["west"];
53650 var east = rs["east"];
53651 var center = rs["center"];
53652 //if(this.hideOnLayout){ // not supported anymore
53653 //c.el.setStyle("display", "none");
53655 if(north && north.isVisible()){
53656 var b = north.getBox();
53657 var m = north.getMargins();
53658 b.width = w - (m.left+m.right);
53661 centerY = b.height + b.y + m.bottom;
53662 centerH -= centerY;
53663 north.updateBox(this.safeBox(b));
53665 if(south && south.isVisible()){
53666 var b = south.getBox();
53667 var m = south.getMargins();
53668 b.width = w - (m.left+m.right);
53670 var totalHeight = (b.height + m.top + m.bottom);
53671 b.y = h - totalHeight + m.top;
53672 centerH -= totalHeight;
53673 south.updateBox(this.safeBox(b));
53675 if(west && west.isVisible()){
53676 var b = west.getBox();
53677 var m = west.getMargins();
53678 b.height = centerH - (m.top+m.bottom);
53680 b.y = centerY + m.top;
53681 var totalWidth = (b.width + m.left + m.right);
53682 centerX += totalWidth;
53683 centerW -= totalWidth;
53684 west.updateBox(this.safeBox(b));
53686 if(east && east.isVisible()){
53687 var b = east.getBox();
53688 var m = east.getMargins();
53689 b.height = centerH - (m.top+m.bottom);
53690 var totalWidth = (b.width + m.left + m.right);
53691 b.x = w - totalWidth + m.left;
53692 b.y = centerY + m.top;
53693 centerW -= totalWidth;
53694 east.updateBox(this.safeBox(b));
53697 var m = center.getMargins();
53699 x: centerX + m.left,
53700 y: centerY + m.top,
53701 width: centerW - (m.left+m.right),
53702 height: centerH - (m.top+m.bottom)
53704 //if(this.hideOnLayout){
53705 //center.el.setStyle("display", "block");
53707 center.updateBox(this.safeBox(centerBox));
53710 this.fireEvent("layout", this);
53714 safeBox : function(box){
53715 box.width = Math.max(0, box.width);
53716 box.height = Math.max(0, box.height);
53721 * Adds a ContentPanel (or subclass) to this layout.
53722 * @param {String} target The target region key (north, south, east, west or center).
53723 * @param {Roo.ContentPanel} panel The panel to add
53724 * @return {Roo.ContentPanel} The added panel
53726 add : function(target, panel){
53728 target = target.toLowerCase();
53729 return this.regions[target].add(panel);
53733 * Remove a ContentPanel (or subclass) to this layout.
53734 * @param {String} target The target region key (north, south, east, west or center).
53735 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
53736 * @return {Roo.ContentPanel} The removed panel
53738 remove : function(target, panel){
53739 target = target.toLowerCase();
53740 return this.regions[target].remove(panel);
53744 * Searches all regions for a panel with the specified id
53745 * @param {String} panelId
53746 * @return {Roo.ContentPanel} The panel or null if it wasn't found
53748 findPanel : function(panelId){
53749 var rs = this.regions;
53750 for(var target in rs){
53751 if(typeof rs[target] != "function"){
53752 var p = rs[target].getPanel(panelId);
53762 * Searches all regions for a panel with the specified id and activates (shows) it.
53763 * @param {String/ContentPanel} panelId The panels id or the panel itself
53764 * @return {Roo.ContentPanel} The shown panel or null
53766 showPanel : function(panelId) {
53767 var rs = this.regions;
53768 for(var target in rs){
53769 var r = rs[target];
53770 if(typeof r != "function"){
53771 if(r.hasPanel(panelId)){
53772 return r.showPanel(panelId);
53780 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
53781 * @param {Roo.state.Provider} provider (optional) An alternate state provider
53783 restoreState : function(provider){
53785 provider = Roo.state.Manager;
53787 var sm = new Roo.LayoutStateManager();
53788 sm.init(this, provider);
53792 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
53793 * object should contain properties for each region to add ContentPanels to, and each property's value should be
53794 * a valid ContentPanel config object. Example:
53796 // Create the main layout
53797 var layout = new Roo.BorderLayout('main-ct', {
53808 // Create and add multiple ContentPanels at once via configs
53811 id: 'source-files',
53813 title:'Ext Source Files',
53826 * @param {Object} regions An object containing ContentPanel configs by region name
53828 batchAdd : function(regions){
53829 this.beginUpdate();
53830 for(var rname in regions){
53831 var lr = this.regions[rname];
53833 this.addTypedPanels(lr, regions[rname]);
53840 addTypedPanels : function(lr, ps){
53841 if(typeof ps == 'string'){
53842 lr.add(new Roo.ContentPanel(ps));
53844 else if(ps instanceof Array){
53845 for(var i =0, len = ps.length; i < len; i++){
53846 this.addTypedPanels(lr, ps[i]);
53849 else if(!ps.events){ // raw config?
53851 delete ps.el; // prevent conflict
53852 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
53854 else { // panel object assumed!
53859 * Adds a xtype elements to the layout.
53863 xtype : 'ContentPanel',
53870 xtype : 'NestedLayoutPanel',
53876 items : [ ... list of content panels or nested layout panels.. ]
53880 * @param {Object} cfg Xtype definition of item to add.
53882 addxtype : function(cfg)
53884 // basically accepts a pannel...
53885 // can accept a layout region..!?!?
53886 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
53888 if (!cfg.xtype.match(/Panel$/)) {
53893 if (typeof(cfg.region) == 'undefined') {
53894 Roo.log("Failed to add Panel, region was not set");
53898 var region = cfg.region;
53904 xitems = cfg.items;
53911 case 'ContentPanel': // ContentPanel (el, cfg)
53912 case 'ScrollPanel': // ContentPanel (el, cfg)
53914 if(cfg.autoCreate) {
53915 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
53917 var el = this.el.createChild();
53918 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
53921 this.add(region, ret);
53925 case 'TreePanel': // our new panel!
53926 cfg.el = this.el.createChild();
53927 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
53928 this.add(region, ret);
53931 case 'NestedLayoutPanel':
53932 // create a new Layout (which is a Border Layout...
53933 var el = this.el.createChild();
53934 var clayout = cfg.layout;
53936 clayout.items = clayout.items || [];
53937 // replace this exitems with the clayout ones..
53938 xitems = clayout.items;
53941 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
53942 cfg.background = false;
53944 var layout = new Roo.BorderLayout(el, clayout);
53946 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
53947 //console.log('adding nested layout panel ' + cfg.toSource());
53948 this.add(region, ret);
53949 nb = {}; /// find first...
53954 // needs grid and region
53956 //var el = this.getRegion(region).el.createChild();
53957 var el = this.el.createChild();
53958 // create the grid first...
53960 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
53962 if (region == 'center' && this.active ) {
53963 cfg.background = false;
53965 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
53967 this.add(region, ret);
53968 if (cfg.background) {
53969 ret.on('activate', function(gp) {
53970 if (!gp.grid.rendered) {
53985 if (typeof(Roo[cfg.xtype]) != 'undefined') {
53987 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
53988 this.add(region, ret);
53991 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
53995 // GridPanel (grid, cfg)
53998 this.beginUpdate();
54002 Roo.each(xitems, function(i) {
54003 region = nb && i.region ? i.region : false;
54005 var add = ret.addxtype(i);
54008 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
54009 if (!i.background) {
54010 abn[region] = nb[region] ;
54017 // make the last non-background panel active..
54018 //if (nb) { Roo.log(abn); }
54021 for(var r in abn) {
54022 region = this.getRegion(r);
54024 // tried using nb[r], but it does not work..
54026 region.showPanel(abn[r]);
54037 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
54038 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
54039 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
54040 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
54043 var CP = Roo.ContentPanel;
54045 var layout = Roo.BorderLayout.create({
54049 panels: [new CP("north", "North")]
54058 panels: [new CP("west", {title: "West"})]
54067 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
54076 panels: [new CP("south", {title: "South", closable: true})]
54083 preferredTabWidth: 150,
54085 new CP("center1", {title: "Close Me", closable: true}),
54086 new CP("center2", {title: "Center Panel", closable: false})
54091 layout.getRegion("center").showPanel("center1");
54096 Roo.BorderLayout.create = function(config, targetEl){
54097 var layout = new Roo.BorderLayout(targetEl || document.body, config);
54098 layout.beginUpdate();
54099 var regions = Roo.BorderLayout.RegionFactory.validRegions;
54100 for(var j = 0, jlen = regions.length; j < jlen; j++){
54101 var lr = regions[j];
54102 if(layout.regions[lr] && config[lr].panels){
54103 var r = layout.regions[lr];
54104 var ps = config[lr].panels;
54105 layout.addTypedPanels(r, ps);
54108 layout.endUpdate();
54113 Roo.BorderLayout.RegionFactory = {
54115 validRegions : ["north","south","east","west","center"],
54118 create : function(target, mgr, config){
54119 target = target.toLowerCase();
54120 if(config.lightweight || config.basic){
54121 return new Roo.BasicLayoutRegion(mgr, config, target);
54125 return new Roo.NorthLayoutRegion(mgr, config);
54127 return new Roo.SouthLayoutRegion(mgr, config);
54129 return new Roo.EastLayoutRegion(mgr, config);
54131 return new Roo.WestLayoutRegion(mgr, config);
54133 return new Roo.CenterLayoutRegion(mgr, config);
54135 throw 'Layout region "'+target+'" not supported.';
54139 * Ext JS Library 1.1.1
54140 * Copyright(c) 2006-2007, Ext JS, LLC.
54142 * Originally Released Under LGPL - original licence link has changed is not relivant.
54145 * <script type="text/javascript">
54149 * @class Roo.BasicLayoutRegion
54150 * @extends Roo.util.Observable
54151 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
54152 * and does not have a titlebar, tabs or any other features. All it does is size and position
54153 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
54155 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
54157 this.position = pos;
54160 * @scope Roo.BasicLayoutRegion
54164 * @event beforeremove
54165 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
54166 * @param {Roo.LayoutRegion} this
54167 * @param {Roo.ContentPanel} panel The panel
54168 * @param {Object} e The cancel event object
54170 "beforeremove" : true,
54172 * @event invalidated
54173 * Fires when the layout for this region is changed.
54174 * @param {Roo.LayoutRegion} this
54176 "invalidated" : true,
54178 * @event visibilitychange
54179 * Fires when this region is shown or hidden
54180 * @param {Roo.LayoutRegion} this
54181 * @param {Boolean} visibility true or false
54183 "visibilitychange" : true,
54185 * @event paneladded
54186 * Fires when a panel is added.
54187 * @param {Roo.LayoutRegion} this
54188 * @param {Roo.ContentPanel} panel The panel
54190 "paneladded" : true,
54192 * @event panelremoved
54193 * Fires when a panel is removed.
54194 * @param {Roo.LayoutRegion} this
54195 * @param {Roo.ContentPanel} panel The panel
54197 "panelremoved" : true,
54199 * @event beforecollapse
54200 * Fires when this region before collapse.
54201 * @param {Roo.LayoutRegion} this
54203 "beforecollapse" : true,
54206 * Fires when this region is collapsed.
54207 * @param {Roo.LayoutRegion} this
54209 "collapsed" : true,
54212 * Fires when this region is expanded.
54213 * @param {Roo.LayoutRegion} this
54218 * Fires when this region is slid into view.
54219 * @param {Roo.LayoutRegion} this
54221 "slideshow" : true,
54224 * Fires when this region slides out of view.
54225 * @param {Roo.LayoutRegion} this
54227 "slidehide" : true,
54229 * @event panelactivated
54230 * Fires when a panel is activated.
54231 * @param {Roo.LayoutRegion} this
54232 * @param {Roo.ContentPanel} panel The activated panel
54234 "panelactivated" : true,
54237 * Fires when the user resizes this region.
54238 * @param {Roo.LayoutRegion} this
54239 * @param {Number} newSize The new size (width for east/west, height for north/south)
54243 /** A collection of panels in this region. @type Roo.util.MixedCollection */
54244 this.panels = new Roo.util.MixedCollection();
54245 this.panels.getKey = this.getPanelId.createDelegate(this);
54247 this.activePanel = null;
54248 // ensure listeners are added...
54250 if (config.listeners || config.events) {
54251 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
54252 listeners : config.listeners || {},
54253 events : config.events || {}
54257 if(skipConfig !== true){
54258 this.applyConfig(config);
54262 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
54263 getPanelId : function(p){
54267 applyConfig : function(config){
54268 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
54269 this.config = config;
54274 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
54275 * the width, for horizontal (north, south) the height.
54276 * @param {Number} newSize The new width or height
54278 resizeTo : function(newSize){
54279 var el = this.el ? this.el :
54280 (this.activePanel ? this.activePanel.getEl() : null);
54282 switch(this.position){
54285 el.setWidth(newSize);
54286 this.fireEvent("resized", this, newSize);
54290 el.setHeight(newSize);
54291 this.fireEvent("resized", this, newSize);
54297 getBox : function(){
54298 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
54301 getMargins : function(){
54302 return this.margins;
54305 updateBox : function(box){
54307 var el = this.activePanel.getEl();
54308 el.dom.style.left = box.x + "px";
54309 el.dom.style.top = box.y + "px";
54310 this.activePanel.setSize(box.width, box.height);
54314 * Returns the container element for this region.
54315 * @return {Roo.Element}
54317 getEl : function(){
54318 return this.activePanel;
54322 * Returns true if this region is currently visible.
54323 * @return {Boolean}
54325 isVisible : function(){
54326 return this.activePanel ? true : false;
54329 setActivePanel : function(panel){
54330 panel = this.getPanel(panel);
54331 if(this.activePanel && this.activePanel != panel){
54332 this.activePanel.setActiveState(false);
54333 this.activePanel.getEl().setLeftTop(-10000,-10000);
54335 this.activePanel = panel;
54336 panel.setActiveState(true);
54338 panel.setSize(this.box.width, this.box.height);
54340 this.fireEvent("panelactivated", this, panel);
54341 this.fireEvent("invalidated");
54345 * Show the specified panel.
54346 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
54347 * @return {Roo.ContentPanel} The shown panel or null
54349 showPanel : function(panel){
54350 if(panel = this.getPanel(panel)){
54351 this.setActivePanel(panel);
54357 * Get the active panel for this region.
54358 * @return {Roo.ContentPanel} The active panel or null
54360 getActivePanel : function(){
54361 return this.activePanel;
54365 * Add the passed ContentPanel(s)
54366 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
54367 * @return {Roo.ContentPanel} The panel added (if only one was added)
54369 add : function(panel){
54370 if(arguments.length > 1){
54371 for(var i = 0, len = arguments.length; i < len; i++) {
54372 this.add(arguments[i]);
54376 if(this.hasPanel(panel)){
54377 this.showPanel(panel);
54380 var el = panel.getEl();
54381 if(el.dom.parentNode != this.mgr.el.dom){
54382 this.mgr.el.dom.appendChild(el.dom);
54384 if(panel.setRegion){
54385 panel.setRegion(this);
54387 this.panels.add(panel);
54388 el.setStyle("position", "absolute");
54389 if(!panel.background){
54390 this.setActivePanel(panel);
54391 if(this.config.initialSize && this.panels.getCount()==1){
54392 this.resizeTo(this.config.initialSize);
54395 this.fireEvent("paneladded", this, panel);
54400 * Returns true if the panel is in this region.
54401 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
54402 * @return {Boolean}
54404 hasPanel : function(panel){
54405 if(typeof panel == "object"){ // must be panel obj
54406 panel = panel.getId();
54408 return this.getPanel(panel) ? true : false;
54412 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
54413 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
54414 * @param {Boolean} preservePanel Overrides the config preservePanel option
54415 * @return {Roo.ContentPanel} The panel that was removed
54417 remove : function(panel, preservePanel){
54418 panel = this.getPanel(panel);
54423 this.fireEvent("beforeremove", this, panel, e);
54424 if(e.cancel === true){
54427 var panelId = panel.getId();
54428 this.panels.removeKey(panelId);
54433 * Returns the panel specified or null if it's not in this region.
54434 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
54435 * @return {Roo.ContentPanel}
54437 getPanel : function(id){
54438 if(typeof id == "object"){ // must be panel obj
54441 return this.panels.get(id);
54445 * Returns this regions position (north/south/east/west/center).
54448 getPosition: function(){
54449 return this.position;
54453 * Ext JS Library 1.1.1
54454 * Copyright(c) 2006-2007, Ext JS, LLC.
54456 * Originally Released Under LGPL - original licence link has changed is not relivant.
54459 * <script type="text/javascript">
54463 * @class Roo.LayoutRegion
54464 * @extends Roo.BasicLayoutRegion
54465 * This class represents a region in a layout manager.
54466 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
54467 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
54468 * @cfg {Boolean} floatable False to disable floating (defaults to true)
54469 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
54470 * @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})
54471 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
54472 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
54473 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
54474 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
54475 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
54476 * @cfg {String} title The title for the region (overrides panel titles)
54477 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
54478 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
54479 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
54480 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
54481 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
54482 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
54483 * the space available, similar to FireFox 1.5 tabs (defaults to false)
54484 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
54485 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
54486 * @cfg {Boolean} showPin True to show a pin button
54487 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
54488 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
54489 * @cfg {Boolean} disableTabTips True to disable tab tooltips
54490 * @cfg {Number} width For East/West panels
54491 * @cfg {Number} height For North/South panels
54492 * @cfg {Boolean} split To show the splitter
54493 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
54495 Roo.LayoutRegion = function(mgr, config, pos){
54496 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
54497 var dh = Roo.DomHelper;
54498 /** This region's container element
54499 * @type Roo.Element */
54500 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
54501 /** This region's title element
54502 * @type Roo.Element */
54504 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
54505 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
54506 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
54508 this.titleEl.enableDisplayMode();
54509 /** This region's title text element
54510 * @type HTMLElement */
54511 this.titleTextEl = this.titleEl.dom.firstChild;
54512 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
54513 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
54514 this.closeBtn.enableDisplayMode();
54515 this.closeBtn.on("click", this.closeClicked, this);
54516 this.closeBtn.hide();
54518 this.createBody(config);
54519 this.visible = true;
54520 this.collapsed = false;
54522 if(config.hideWhenEmpty){
54524 this.on("paneladded", this.validateVisibility, this);
54525 this.on("panelremoved", this.validateVisibility, this);
54527 this.applyConfig(config);
54530 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
54532 createBody : function(){
54533 /** This region's body element
54534 * @type Roo.Element */
54535 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
54538 applyConfig : function(c){
54539 if(c.collapsible && this.position != "center" && !this.collapsedEl){
54540 var dh = Roo.DomHelper;
54541 if(c.titlebar !== false){
54542 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
54543 this.collapseBtn.on("click", this.collapse, this);
54544 this.collapseBtn.enableDisplayMode();
54546 if(c.showPin === true || this.showPin){
54547 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
54548 this.stickBtn.enableDisplayMode();
54549 this.stickBtn.on("click", this.expand, this);
54550 this.stickBtn.hide();
54553 /** This region's collapsed element
54554 * @type Roo.Element */
54555 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
54556 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
54558 if(c.floatable !== false){
54559 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
54560 this.collapsedEl.on("click", this.collapseClick, this);
54563 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
54564 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
54565 id: "message", unselectable: "on", style:{"float":"left"}});
54566 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
54568 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
54569 this.expandBtn.on("click", this.expand, this);
54571 if(this.collapseBtn){
54572 this.collapseBtn.setVisible(c.collapsible == true);
54574 this.cmargins = c.cmargins || this.cmargins ||
54575 (this.position == "west" || this.position == "east" ?
54576 {top: 0, left: 2, right:2, bottom: 0} :
54577 {top: 2, left: 0, right:0, bottom: 2});
54578 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
54579 this.bottomTabs = c.tabPosition != "top";
54580 this.autoScroll = c.autoScroll || false;
54581 if(this.autoScroll){
54582 this.bodyEl.setStyle("overflow", "auto");
54584 this.bodyEl.setStyle("overflow", "hidden");
54586 //if(c.titlebar !== false){
54587 if((!c.titlebar && !c.title) || c.titlebar === false){
54588 this.titleEl.hide();
54590 this.titleEl.show();
54592 this.titleTextEl.innerHTML = c.title;
54596 this.duration = c.duration || .30;
54597 this.slideDuration = c.slideDuration || .45;
54600 this.collapse(true);
54607 * Returns true if this region is currently visible.
54608 * @return {Boolean}
54610 isVisible : function(){
54611 return this.visible;
54615 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
54616 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
54618 setCollapsedTitle : function(title){
54619 title = title || " ";
54620 if(this.collapsedTitleTextEl){
54621 this.collapsedTitleTextEl.innerHTML = title;
54625 getBox : function(){
54627 if(!this.collapsed){
54628 b = this.el.getBox(false, true);
54630 b = this.collapsedEl.getBox(false, true);
54635 getMargins : function(){
54636 return this.collapsed ? this.cmargins : this.margins;
54639 highlight : function(){
54640 this.el.addClass("x-layout-panel-dragover");
54643 unhighlight : function(){
54644 this.el.removeClass("x-layout-panel-dragover");
54647 updateBox : function(box){
54649 if(!this.collapsed){
54650 this.el.dom.style.left = box.x + "px";
54651 this.el.dom.style.top = box.y + "px";
54652 this.updateBody(box.width, box.height);
54654 this.collapsedEl.dom.style.left = box.x + "px";
54655 this.collapsedEl.dom.style.top = box.y + "px";
54656 this.collapsedEl.setSize(box.width, box.height);
54659 this.tabs.autoSizeTabs();
54663 updateBody : function(w, h){
54665 this.el.setWidth(w);
54666 w -= this.el.getBorderWidth("rl");
54667 if(this.config.adjustments){
54668 w += this.config.adjustments[0];
54672 this.el.setHeight(h);
54673 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
54674 h -= this.el.getBorderWidth("tb");
54675 if(this.config.adjustments){
54676 h += this.config.adjustments[1];
54678 this.bodyEl.setHeight(h);
54680 h = this.tabs.syncHeight(h);
54683 if(this.panelSize){
54684 w = w !== null ? w : this.panelSize.width;
54685 h = h !== null ? h : this.panelSize.height;
54687 if(this.activePanel){
54688 var el = this.activePanel.getEl();
54689 w = w !== null ? w : el.getWidth();
54690 h = h !== null ? h : el.getHeight();
54691 this.panelSize = {width: w, height: h};
54692 this.activePanel.setSize(w, h);
54694 if(Roo.isIE && this.tabs){
54695 this.tabs.el.repaint();
54700 * Returns the container element for this region.
54701 * @return {Roo.Element}
54703 getEl : function(){
54708 * Hides this region.
54711 if(!this.collapsed){
54712 this.el.dom.style.left = "-2000px";
54715 this.collapsedEl.dom.style.left = "-2000px";
54716 this.collapsedEl.hide();
54718 this.visible = false;
54719 this.fireEvent("visibilitychange", this, false);
54723 * Shows this region if it was previously hidden.
54726 if(!this.collapsed){
54729 this.collapsedEl.show();
54731 this.visible = true;
54732 this.fireEvent("visibilitychange", this, true);
54735 closeClicked : function(){
54736 if(this.activePanel){
54737 this.remove(this.activePanel);
54741 collapseClick : function(e){
54743 e.stopPropagation();
54746 e.stopPropagation();
54752 * Collapses this region.
54753 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
54755 collapse : function(skipAnim, skipCheck){
54756 if(this.collapsed) {
54760 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
54762 this.collapsed = true;
54764 this.split.el.hide();
54766 if(this.config.animate && skipAnim !== true){
54767 this.fireEvent("invalidated", this);
54768 this.animateCollapse();
54770 this.el.setLocation(-20000,-20000);
54772 this.collapsedEl.show();
54773 this.fireEvent("collapsed", this);
54774 this.fireEvent("invalidated", this);
54780 animateCollapse : function(){
54785 * Expands this region if it was previously collapsed.
54786 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
54787 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
54789 expand : function(e, skipAnim){
54791 e.stopPropagation();
54793 if(!this.collapsed || this.el.hasActiveFx()) {
54797 this.afterSlideIn();
54800 this.collapsed = false;
54801 if(this.config.animate && skipAnim !== true){
54802 this.animateExpand();
54806 this.split.el.show();
54808 this.collapsedEl.setLocation(-2000,-2000);
54809 this.collapsedEl.hide();
54810 this.fireEvent("invalidated", this);
54811 this.fireEvent("expanded", this);
54815 animateExpand : function(){
54819 initTabs : function()
54821 this.bodyEl.setStyle("overflow", "hidden");
54822 var ts = new Roo.TabPanel(
54825 tabPosition: this.bottomTabs ? 'bottom' : 'top',
54826 disableTooltips: this.config.disableTabTips,
54827 toolbar : this.config.toolbar
54830 if(this.config.hideTabs){
54831 ts.stripWrap.setDisplayed(false);
54834 ts.resizeTabs = this.config.resizeTabs === true;
54835 ts.minTabWidth = this.config.minTabWidth || 40;
54836 ts.maxTabWidth = this.config.maxTabWidth || 250;
54837 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
54838 ts.monitorResize = false;
54839 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
54840 ts.bodyEl.addClass('x-layout-tabs-body');
54841 this.panels.each(this.initPanelAsTab, this);
54844 initPanelAsTab : function(panel){
54845 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
54846 this.config.closeOnTab && panel.isClosable());
54847 if(panel.tabTip !== undefined){
54848 ti.setTooltip(panel.tabTip);
54850 ti.on("activate", function(){
54851 this.setActivePanel(panel);
54853 if(this.config.closeOnTab){
54854 ti.on("beforeclose", function(t, e){
54856 this.remove(panel);
54862 updatePanelTitle : function(panel, title){
54863 if(this.activePanel == panel){
54864 this.updateTitle(title);
54867 var ti = this.tabs.getTab(panel.getEl().id);
54869 if(panel.tabTip !== undefined){
54870 ti.setTooltip(panel.tabTip);
54875 updateTitle : function(title){
54876 if(this.titleTextEl && !this.config.title){
54877 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
54881 setActivePanel : function(panel){
54882 panel = this.getPanel(panel);
54883 if(this.activePanel && this.activePanel != panel){
54884 this.activePanel.setActiveState(false);
54886 this.activePanel = panel;
54887 panel.setActiveState(true);
54888 if(this.panelSize){
54889 panel.setSize(this.panelSize.width, this.panelSize.height);
54892 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
54894 this.updateTitle(panel.getTitle());
54896 this.fireEvent("invalidated", this);
54898 this.fireEvent("panelactivated", this, panel);
54902 * Shows the specified panel.
54903 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
54904 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
54906 showPanel : function(panel)
54908 panel = this.getPanel(panel);
54911 var tab = this.tabs.getTab(panel.getEl().id);
54912 if(tab.isHidden()){
54913 this.tabs.unhideTab(tab.id);
54917 this.setActivePanel(panel);
54924 * Get the active panel for this region.
54925 * @return {Roo.ContentPanel} The active panel or null
54927 getActivePanel : function(){
54928 return this.activePanel;
54931 validateVisibility : function(){
54932 if(this.panels.getCount() < 1){
54933 this.updateTitle(" ");
54934 this.closeBtn.hide();
54937 if(!this.isVisible()){
54944 * Adds the passed ContentPanel(s) to this region.
54945 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
54946 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
54948 add : function(panel){
54949 if(arguments.length > 1){
54950 for(var i = 0, len = arguments.length; i < len; i++) {
54951 this.add(arguments[i]);
54955 if(this.hasPanel(panel)){
54956 this.showPanel(panel);
54959 panel.setRegion(this);
54960 this.panels.add(panel);
54961 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
54962 this.bodyEl.dom.appendChild(panel.getEl().dom);
54963 if(panel.background !== true){
54964 this.setActivePanel(panel);
54966 this.fireEvent("paneladded", this, panel);
54972 this.initPanelAsTab(panel);
54974 if(panel.background !== true){
54975 this.tabs.activate(panel.getEl().id);
54977 this.fireEvent("paneladded", this, panel);
54982 * Hides the tab for the specified panel.
54983 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
54985 hidePanel : function(panel){
54986 if(this.tabs && (panel = this.getPanel(panel))){
54987 this.tabs.hideTab(panel.getEl().id);
54992 * Unhides the tab for a previously hidden panel.
54993 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
54995 unhidePanel : function(panel){
54996 if(this.tabs && (panel = this.getPanel(panel))){
54997 this.tabs.unhideTab(panel.getEl().id);
55001 clearPanels : function(){
55002 while(this.panels.getCount() > 0){
55003 this.remove(this.panels.first());
55008 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
55009 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
55010 * @param {Boolean} preservePanel Overrides the config preservePanel option
55011 * @return {Roo.ContentPanel} The panel that was removed
55013 remove : function(panel, preservePanel){
55014 panel = this.getPanel(panel);
55019 this.fireEvent("beforeremove", this, panel, e);
55020 if(e.cancel === true){
55023 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
55024 var panelId = panel.getId();
55025 this.panels.removeKey(panelId);
55027 document.body.appendChild(panel.getEl().dom);
55030 this.tabs.removeTab(panel.getEl().id);
55031 }else if (!preservePanel){
55032 this.bodyEl.dom.removeChild(panel.getEl().dom);
55034 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
55035 var p = this.panels.first();
55036 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
55037 tempEl.appendChild(p.getEl().dom);
55038 this.bodyEl.update("");
55039 this.bodyEl.dom.appendChild(p.getEl().dom);
55041 this.updateTitle(p.getTitle());
55043 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
55044 this.setActivePanel(p);
55046 panel.setRegion(null);
55047 if(this.activePanel == panel){
55048 this.activePanel = null;
55050 if(this.config.autoDestroy !== false && preservePanel !== true){
55051 try{panel.destroy();}catch(e){}
55053 this.fireEvent("panelremoved", this, panel);
55058 * Returns the TabPanel component used by this region
55059 * @return {Roo.TabPanel}
55061 getTabs : function(){
55065 createTool : function(parentEl, className){
55066 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
55067 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
55068 btn.addClassOnOver("x-layout-tools-button-over");
55073 * Ext JS Library 1.1.1
55074 * Copyright(c) 2006-2007, Ext JS, LLC.
55076 * Originally Released Under LGPL - original licence link has changed is not relivant.
55079 * <script type="text/javascript">
55085 * @class Roo.SplitLayoutRegion
55086 * @extends Roo.LayoutRegion
55087 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
55089 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
55090 this.cursor = cursor;
55091 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
55094 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
55095 splitTip : "Drag to resize.",
55096 collapsibleSplitTip : "Drag to resize. Double click to hide.",
55097 useSplitTips : false,
55099 applyConfig : function(config){
55100 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
55103 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
55104 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
55105 /** The SplitBar for this region
55106 * @type Roo.SplitBar */
55107 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
55108 this.split.on("moved", this.onSplitMove, this);
55109 this.split.useShim = config.useShim === true;
55110 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
55111 if(this.useSplitTips){
55112 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
55114 if(config.collapsible){
55115 this.split.el.on("dblclick", this.collapse, this);
55118 if(typeof config.minSize != "undefined"){
55119 this.split.minSize = config.minSize;
55121 if(typeof config.maxSize != "undefined"){
55122 this.split.maxSize = config.maxSize;
55124 if(config.hideWhenEmpty || config.hidden || config.collapsed){
55125 this.hideSplitter();
55130 getHMaxSize : function(){
55131 var cmax = this.config.maxSize || 10000;
55132 var center = this.mgr.getRegion("center");
55133 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
55136 getVMaxSize : function(){
55137 var cmax = this.config.maxSize || 10000;
55138 var center = this.mgr.getRegion("center");
55139 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
55142 onSplitMove : function(split, newSize){
55143 this.fireEvent("resized", this, newSize);
55147 * Returns the {@link Roo.SplitBar} for this region.
55148 * @return {Roo.SplitBar}
55150 getSplitBar : function(){
55155 this.hideSplitter();
55156 Roo.SplitLayoutRegion.superclass.hide.call(this);
55159 hideSplitter : function(){
55161 this.split.el.setLocation(-2000,-2000);
55162 this.split.el.hide();
55168 this.split.el.show();
55170 Roo.SplitLayoutRegion.superclass.show.call(this);
55173 beforeSlide: function(){
55174 if(Roo.isGecko){// firefox overflow auto bug workaround
55175 this.bodyEl.clip();
55177 this.tabs.bodyEl.clip();
55179 if(this.activePanel){
55180 this.activePanel.getEl().clip();
55182 if(this.activePanel.beforeSlide){
55183 this.activePanel.beforeSlide();
55189 afterSlide : function(){
55190 if(Roo.isGecko){// firefox overflow auto bug workaround
55191 this.bodyEl.unclip();
55193 this.tabs.bodyEl.unclip();
55195 if(this.activePanel){
55196 this.activePanel.getEl().unclip();
55197 if(this.activePanel.afterSlide){
55198 this.activePanel.afterSlide();
55204 initAutoHide : function(){
55205 if(this.autoHide !== false){
55206 if(!this.autoHideHd){
55207 var st = new Roo.util.DelayedTask(this.slideIn, this);
55208 this.autoHideHd = {
55209 "mouseout": function(e){
55210 if(!e.within(this.el, true)){
55214 "mouseover" : function(e){
55220 this.el.on(this.autoHideHd);
55224 clearAutoHide : function(){
55225 if(this.autoHide !== false){
55226 this.el.un("mouseout", this.autoHideHd.mouseout);
55227 this.el.un("mouseover", this.autoHideHd.mouseover);
55231 clearMonitor : function(){
55232 Roo.get(document).un("click", this.slideInIf, this);
55235 // these names are backwards but not changed for compat
55236 slideOut : function(){
55237 if(this.isSlid || this.el.hasActiveFx()){
55240 this.isSlid = true;
55241 if(this.collapseBtn){
55242 this.collapseBtn.hide();
55244 this.closeBtnState = this.closeBtn.getStyle('display');
55245 this.closeBtn.hide();
55247 this.stickBtn.show();
55250 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
55251 this.beforeSlide();
55252 this.el.setStyle("z-index", 10001);
55253 this.el.slideIn(this.getSlideAnchor(), {
55254 callback: function(){
55256 this.initAutoHide();
55257 Roo.get(document).on("click", this.slideInIf, this);
55258 this.fireEvent("slideshow", this);
55265 afterSlideIn : function(){
55266 this.clearAutoHide();
55267 this.isSlid = false;
55268 this.clearMonitor();
55269 this.el.setStyle("z-index", "");
55270 if(this.collapseBtn){
55271 this.collapseBtn.show();
55273 this.closeBtn.setStyle('display', this.closeBtnState);
55275 this.stickBtn.hide();
55277 this.fireEvent("slidehide", this);
55280 slideIn : function(cb){
55281 if(!this.isSlid || this.el.hasActiveFx()){
55285 this.isSlid = false;
55286 this.beforeSlide();
55287 this.el.slideOut(this.getSlideAnchor(), {
55288 callback: function(){
55289 this.el.setLeftTop(-10000, -10000);
55291 this.afterSlideIn();
55299 slideInIf : function(e){
55300 if(!e.within(this.el)){
55305 animateCollapse : function(){
55306 this.beforeSlide();
55307 this.el.setStyle("z-index", 20000);
55308 var anchor = this.getSlideAnchor();
55309 this.el.slideOut(anchor, {
55310 callback : function(){
55311 this.el.setStyle("z-index", "");
55312 this.collapsedEl.slideIn(anchor, {duration:.3});
55314 this.el.setLocation(-10000,-10000);
55316 this.fireEvent("collapsed", this);
55323 animateExpand : function(){
55324 this.beforeSlide();
55325 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
55326 this.el.setStyle("z-index", 20000);
55327 this.collapsedEl.hide({
55330 this.el.slideIn(this.getSlideAnchor(), {
55331 callback : function(){
55332 this.el.setStyle("z-index", "");
55335 this.split.el.show();
55337 this.fireEvent("invalidated", this);
55338 this.fireEvent("expanded", this);
55366 getAnchor : function(){
55367 return this.anchors[this.position];
55370 getCollapseAnchor : function(){
55371 return this.canchors[this.position];
55374 getSlideAnchor : function(){
55375 return this.sanchors[this.position];
55378 getAlignAdj : function(){
55379 var cm = this.cmargins;
55380 switch(this.position){
55396 getExpandAdj : function(){
55397 var c = this.collapsedEl, cm = this.cmargins;
55398 switch(this.position){
55400 return [-(cm.right+c.getWidth()+cm.left), 0];
55403 return [cm.right+c.getWidth()+cm.left, 0];
55406 return [0, -(cm.top+cm.bottom+c.getHeight())];
55409 return [0, cm.top+cm.bottom+c.getHeight()];
55415 * Ext JS Library 1.1.1
55416 * Copyright(c) 2006-2007, Ext JS, LLC.
55418 * Originally Released Under LGPL - original licence link has changed is not relivant.
55421 * <script type="text/javascript">
55424 * These classes are private internal classes
55426 Roo.CenterLayoutRegion = function(mgr, config){
55427 Roo.LayoutRegion.call(this, mgr, config, "center");
55428 this.visible = true;
55429 this.minWidth = config.minWidth || 20;
55430 this.minHeight = config.minHeight || 20;
55433 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
55435 // center panel can't be hidden
55439 // center panel can't be hidden
55442 getMinWidth: function(){
55443 return this.minWidth;
55446 getMinHeight: function(){
55447 return this.minHeight;
55452 Roo.NorthLayoutRegion = function(mgr, config){
55453 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
55455 this.split.placement = Roo.SplitBar.TOP;
55456 this.split.orientation = Roo.SplitBar.VERTICAL;
55457 this.split.el.addClass("x-layout-split-v");
55459 var size = config.initialSize || config.height;
55460 if(typeof size != "undefined"){
55461 this.el.setHeight(size);
55464 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
55465 orientation: Roo.SplitBar.VERTICAL,
55466 getBox : function(){
55467 if(this.collapsed){
55468 return this.collapsedEl.getBox();
55470 var box = this.el.getBox();
55472 box.height += this.split.el.getHeight();
55477 updateBox : function(box){
55478 if(this.split && !this.collapsed){
55479 box.height -= this.split.el.getHeight();
55480 this.split.el.setLeft(box.x);
55481 this.split.el.setTop(box.y+box.height);
55482 this.split.el.setWidth(box.width);
55484 if(this.collapsed){
55485 this.updateBody(box.width, null);
55487 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55491 Roo.SouthLayoutRegion = function(mgr, config){
55492 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
55494 this.split.placement = Roo.SplitBar.BOTTOM;
55495 this.split.orientation = Roo.SplitBar.VERTICAL;
55496 this.split.el.addClass("x-layout-split-v");
55498 var size = config.initialSize || config.height;
55499 if(typeof size != "undefined"){
55500 this.el.setHeight(size);
55503 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
55504 orientation: Roo.SplitBar.VERTICAL,
55505 getBox : function(){
55506 if(this.collapsed){
55507 return this.collapsedEl.getBox();
55509 var box = this.el.getBox();
55511 var sh = this.split.el.getHeight();
55518 updateBox : function(box){
55519 if(this.split && !this.collapsed){
55520 var sh = this.split.el.getHeight();
55523 this.split.el.setLeft(box.x);
55524 this.split.el.setTop(box.y-sh);
55525 this.split.el.setWidth(box.width);
55527 if(this.collapsed){
55528 this.updateBody(box.width, null);
55530 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55534 Roo.EastLayoutRegion = function(mgr, config){
55535 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
55537 this.split.placement = Roo.SplitBar.RIGHT;
55538 this.split.orientation = Roo.SplitBar.HORIZONTAL;
55539 this.split.el.addClass("x-layout-split-h");
55541 var size = config.initialSize || config.width;
55542 if(typeof size != "undefined"){
55543 this.el.setWidth(size);
55546 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
55547 orientation: Roo.SplitBar.HORIZONTAL,
55548 getBox : function(){
55549 if(this.collapsed){
55550 return this.collapsedEl.getBox();
55552 var box = this.el.getBox();
55554 var sw = this.split.el.getWidth();
55561 updateBox : function(box){
55562 if(this.split && !this.collapsed){
55563 var sw = this.split.el.getWidth();
55565 this.split.el.setLeft(box.x);
55566 this.split.el.setTop(box.y);
55567 this.split.el.setHeight(box.height);
55570 if(this.collapsed){
55571 this.updateBody(null, box.height);
55573 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55577 Roo.WestLayoutRegion = function(mgr, config){
55578 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
55580 this.split.placement = Roo.SplitBar.LEFT;
55581 this.split.orientation = Roo.SplitBar.HORIZONTAL;
55582 this.split.el.addClass("x-layout-split-h");
55584 var size = config.initialSize || config.width;
55585 if(typeof size != "undefined"){
55586 this.el.setWidth(size);
55589 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
55590 orientation: Roo.SplitBar.HORIZONTAL,
55591 getBox : function(){
55592 if(this.collapsed){
55593 return this.collapsedEl.getBox();
55595 var box = this.el.getBox();
55597 box.width += this.split.el.getWidth();
55602 updateBox : function(box){
55603 if(this.split && !this.collapsed){
55604 var sw = this.split.el.getWidth();
55606 this.split.el.setLeft(box.x+box.width);
55607 this.split.el.setTop(box.y);
55608 this.split.el.setHeight(box.height);
55610 if(this.collapsed){
55611 this.updateBody(null, box.height);
55613 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55618 * Ext JS Library 1.1.1
55619 * Copyright(c) 2006-2007, Ext JS, LLC.
55621 * Originally Released Under LGPL - original licence link has changed is not relivant.
55624 * <script type="text/javascript">
55629 * Private internal class for reading and applying state
55631 Roo.LayoutStateManager = function(layout){
55632 // default empty state
55641 Roo.LayoutStateManager.prototype = {
55642 init : function(layout, provider){
55643 this.provider = provider;
55644 var state = provider.get(layout.id+"-layout-state");
55646 var wasUpdating = layout.isUpdating();
55648 layout.beginUpdate();
55650 for(var key in state){
55651 if(typeof state[key] != "function"){
55652 var rstate = state[key];
55653 var r = layout.getRegion(key);
55656 r.resizeTo(rstate.size);
55658 if(rstate.collapsed == true){
55661 r.expand(null, true);
55667 layout.endUpdate();
55669 this.state = state;
55671 this.layout = layout;
55672 layout.on("regionresized", this.onRegionResized, this);
55673 layout.on("regioncollapsed", this.onRegionCollapsed, this);
55674 layout.on("regionexpanded", this.onRegionExpanded, this);
55677 storeState : function(){
55678 this.provider.set(this.layout.id+"-layout-state", this.state);
55681 onRegionResized : function(region, newSize){
55682 this.state[region.getPosition()].size = newSize;
55686 onRegionCollapsed : function(region){
55687 this.state[region.getPosition()].collapsed = true;
55691 onRegionExpanded : function(region){
55692 this.state[region.getPosition()].collapsed = false;
55697 * Ext JS Library 1.1.1
55698 * Copyright(c) 2006-2007, Ext JS, LLC.
55700 * Originally Released Under LGPL - original licence link has changed is not relivant.
55703 * <script type="text/javascript">
55706 * @class Roo.ContentPanel
55707 * @extends Roo.util.Observable
55708 * @children Roo.form.Form Roo.JsonView Roo.View
55709 * @parent Roo.BorderLayout Roo.LayoutDialog builder-top
55710 * A basic ContentPanel element.
55711 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
55712 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
55713 * @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
55714 * @cfg {Boolean} closable True if the panel can be closed/removed
55715 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
55716 * @cfg {String|HTMLElement|Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
55717 * @cfg {Roo.Toolbar} toolbar A toolbar for this panel
55718 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
55719 * @cfg {String} title The title for this panel
55720 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
55721 * @cfg {String} url Calls {@link #setUrl} with this value
55722 * @cfg {String} region [required] (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
55723 * @cfg {String|Object} params When used with {@link #url}, calls {@link #setUrl} with this value
55724 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
55725 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
55726 * @cfg {String} style Extra style to add to the content panel
55727 * @cfg {Roo.menu.Menu} menu popup menu
55730 * Create a new ContentPanel.
55731 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
55732 * @param {String/Object} config A string to set only the title or a config object
55733 * @param {String} content (optional) Set the HTML content for this panel
55734 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
55736 Roo.ContentPanel = function(el, config, content){
55740 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
55744 if (config && config.parentLayout) {
55745 el = config.parentLayout.el.createChild();
55748 if(el.autoCreate){ // xtype is available if this is called from factory
55752 this.el = Roo.get(el);
55753 if(!this.el && config && config.autoCreate){
55754 if(typeof config.autoCreate == "object"){
55755 if(!config.autoCreate.id){
55756 config.autoCreate.id = config.id||el;
55758 this.el = Roo.DomHelper.append(document.body,
55759 config.autoCreate, true);
55761 this.el = Roo.DomHelper.append(document.body,
55762 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
55767 this.closable = false;
55768 this.loaded = false;
55769 this.active = false;
55770 if(typeof config == "string"){
55771 this.title = config;
55773 Roo.apply(this, config);
55776 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
55777 this.wrapEl = this.el.wrap();
55778 this.toolbar.container = this.el.insertSibling(false, 'before');
55779 this.toolbar = new Roo.Toolbar(this.toolbar);
55782 // xtype created footer. - not sure if will work as we normally have to render first..
55783 if (this.footer && !this.footer.el && this.footer.xtype) {
55784 if (!this.wrapEl) {
55785 this.wrapEl = this.el.wrap();
55788 this.footer.container = this.wrapEl.createChild();
55790 this.footer = Roo.factory(this.footer, Roo);
55795 this.resizeEl = Roo.get(this.resizeEl, true);
55797 this.resizeEl = this.el;
55799 // handle view.xtype
55807 * Fires when this panel is activated.
55808 * @param {Roo.ContentPanel} this
55812 * @event deactivate
55813 * Fires when this panel is activated.
55814 * @param {Roo.ContentPanel} this
55816 "deactivate" : true,
55820 * Fires when this panel is resized if fitToFrame is true.
55821 * @param {Roo.ContentPanel} this
55822 * @param {Number} width The width after any component adjustments
55823 * @param {Number} height The height after any component adjustments
55829 * Fires when this tab is created
55830 * @param {Roo.ContentPanel} this
55840 if(this.autoScroll){
55841 this.resizeEl.setStyle("overflow", "auto");
55843 // fix randome scrolling
55844 this.el.on('scroll', function() {
55845 Roo.log('fix random scolling');
55846 this.scrollTo('top',0);
55849 content = content || this.content;
55851 this.setContent(content);
55853 if(config && config.url){
55854 this.setUrl(this.url, this.params, this.loadOnce);
55859 Roo.ContentPanel.superclass.constructor.call(this);
55861 if (this.view && typeof(this.view.xtype) != 'undefined') {
55862 this.view.el = this.el.appendChild(document.createElement("div"));
55863 this.view = Roo.factory(this.view);
55864 this.view.render && this.view.render(false, '');
55868 this.fireEvent('render', this);
55871 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
55873 setRegion : function(region){
55874 this.region = region;
55876 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
55878 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
55883 * Returns the toolbar for this Panel if one was configured.
55884 * @return {Roo.Toolbar}
55886 getToolbar : function(){
55887 return this.toolbar;
55890 setActiveState : function(active){
55891 this.active = active;
55893 this.fireEvent("deactivate", this);
55895 this.fireEvent("activate", this);
55899 * Updates this panel's element
55900 * @param {String} content The new content
55901 * @param {Boolean} loadScripts (optional) true to look for and process scripts
55903 setContent : function(content, loadScripts){
55904 this.el.update(content, loadScripts);
55907 ignoreResize : function(w, h){
55908 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
55911 this.lastSize = {width: w, height: h};
55916 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
55917 * @return {Roo.UpdateManager} The UpdateManager
55919 getUpdateManager : function(){
55920 return this.el.getUpdateManager();
55923 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
55924 * @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:
55927 url: "your-url.php",
55928 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
55929 callback: yourFunction,
55930 scope: yourObject, //(optional scope)
55933 text: "Loading...",
55938 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
55939 * 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.
55940 * @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}
55941 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
55942 * @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.
55943 * @return {Roo.ContentPanel} this
55946 var um = this.el.getUpdateManager();
55947 um.update.apply(um, arguments);
55953 * 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.
55954 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
55955 * @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)
55956 * @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)
55957 * @return {Roo.UpdateManager} The UpdateManager
55959 setUrl : function(url, params, loadOnce){
55960 if(this.refreshDelegate){
55961 this.removeListener("activate", this.refreshDelegate);
55963 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
55964 this.on("activate", this.refreshDelegate);
55965 return this.el.getUpdateManager();
55968 _handleRefresh : function(url, params, loadOnce){
55969 if(!loadOnce || !this.loaded){
55970 var updater = this.el.getUpdateManager();
55971 updater.update(url, params, this._setLoaded.createDelegate(this));
55975 _setLoaded : function(){
55976 this.loaded = true;
55980 * Returns this panel's id
55983 getId : function(){
55988 * Returns this panel's element - used by regiosn to add.
55989 * @return {Roo.Element}
55991 getEl : function(){
55992 return this.wrapEl || this.el;
55995 adjustForComponents : function(width, height)
55997 //Roo.log('adjustForComponents ');
55998 if(this.resizeEl != this.el){
55999 width -= this.el.getFrameWidth('lr');
56000 height -= this.el.getFrameWidth('tb');
56003 var te = this.toolbar.getEl();
56004 height -= te.getHeight();
56005 te.setWidth(width);
56008 var te = this.footer.getEl();
56009 //Roo.log("footer:" + te.getHeight());
56011 height -= te.getHeight();
56012 te.setWidth(width);
56016 if(this.adjustments){
56017 width += this.adjustments[0];
56018 height += this.adjustments[1];
56020 return {"width": width, "height": height};
56023 setSize : function(width, height){
56024 if(this.fitToFrame && !this.ignoreResize(width, height)){
56025 if(this.fitContainer && this.resizeEl != this.el){
56026 this.el.setSize(width, height);
56028 var size = this.adjustForComponents(width, height);
56029 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
56030 this.fireEvent('resize', this, size.width, size.height);
56035 * Returns this panel's title
56038 getTitle : function(){
56043 * Set this panel's title
56044 * @param {String} title
56046 setTitle : function(title){
56047 this.title = title;
56049 this.region.updatePanelTitle(this, title);
56054 * Returns true is this panel was configured to be closable
56055 * @return {Boolean}
56057 isClosable : function(){
56058 return this.closable;
56061 beforeSlide : function(){
56063 this.resizeEl.clip();
56066 afterSlide : function(){
56068 this.resizeEl.unclip();
56072 * Force a content refresh from the URL specified in the {@link #setUrl} method.
56073 * Will fail silently if the {@link #setUrl} method has not been called.
56074 * This does not activate the panel, just updates its content.
56076 refresh : function(){
56077 if(this.refreshDelegate){
56078 this.loaded = false;
56079 this.refreshDelegate();
56084 * Destroys this panel
56086 destroy : function(){
56087 this.el.removeAllListeners();
56088 var tempEl = document.createElement("span");
56089 tempEl.appendChild(this.el.dom);
56090 tempEl.innerHTML = "";
56096 * form - if the content panel contains a form - this is a reference to it.
56097 * @type {Roo.form.Form}
56101 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
56102 * This contains a reference to it.
56108 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
56118 * @param {Object} cfg Xtype definition of item to add.
56121 addxtype : function(cfg) {
56123 if (cfg.xtype.match(/^Form$/)) {
56126 //if (this.footer) {
56127 // el = this.footer.container.insertSibling(false, 'before');
56129 el = this.el.createChild();
56132 this.form = new Roo.form.Form(cfg);
56135 if ( this.form.allItems.length) {
56136 this.form.render(el.dom);
56140 // should only have one of theses..
56141 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
56142 // views.. should not be just added - used named prop 'view''
56144 cfg.el = this.el.appendChild(document.createElement("div"));
56147 var ret = new Roo.factory(cfg);
56149 ret.render && ret.render(false, ''); // render blank..
56158 * @class Roo.GridPanel
56159 * @extends Roo.ContentPanel
56161 * Create a new GridPanel.
56162 * @param {Roo.grid.Grid} grid The grid for this panel
56163 * @param {String/Object} config A string to set only the panel's title, or a config object
56165 Roo.GridPanel = function(grid, config){
56168 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
56169 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
56171 this.wrapper.dom.appendChild(grid.getGridEl().dom);
56173 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
56176 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
56178 // xtype created footer. - not sure if will work as we normally have to render first..
56179 if (this.footer && !this.footer.el && this.footer.xtype) {
56181 this.footer.container = this.grid.getView().getFooterPanel(true);
56182 this.footer.dataSource = this.grid.dataSource;
56183 this.footer = Roo.factory(this.footer, Roo);
56187 grid.monitorWindowResize = false; // turn off autosizing
56188 grid.autoHeight = false;
56189 grid.autoWidth = false;
56191 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
56194 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
56195 getId : function(){
56196 return this.grid.id;
56200 * Returns the grid for this panel
56201 * @return {Roo.grid.Grid}
56203 getGrid : function(){
56207 setSize : function(width, height){
56208 if(!this.ignoreResize(width, height)){
56209 var grid = this.grid;
56210 var size = this.adjustForComponents(width, height);
56211 grid.getGridEl().setSize(size.width, size.height);
56216 beforeSlide : function(){
56217 this.grid.getView().scroller.clip();
56220 afterSlide : function(){
56221 this.grid.getView().scroller.unclip();
56224 destroy : function(){
56225 this.grid.destroy();
56227 Roo.GridPanel.superclass.destroy.call(this);
56233 * @class Roo.NestedLayoutPanel
56234 * @extends Roo.ContentPanel
56236 * Create a new NestedLayoutPanel.
56239 * @param {Roo.BorderLayout} layout [required] The layout for this panel
56240 * @param {String/Object} config A string to set only the title or a config object
56242 Roo.NestedLayoutPanel = function(layout, config)
56244 // construct with only one argument..
56245 /* FIXME - implement nicer consturctors
56246 if (layout.layout) {
56248 layout = config.layout;
56249 delete config.layout;
56251 if (layout.xtype && !layout.getEl) {
56252 // then layout needs constructing..
56253 layout = Roo.factory(layout, Roo);
56258 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
56260 layout.monitorWindowResize = false; // turn off autosizing
56261 this.layout = layout;
56262 this.layout.getEl().addClass("x-layout-nested-layout");
56269 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
56271 setSize : function(width, height){
56272 if(!this.ignoreResize(width, height)){
56273 var size = this.adjustForComponents(width, height);
56274 var el = this.layout.getEl();
56275 el.setSize(size.width, size.height);
56276 var touch = el.dom.offsetWidth;
56277 this.layout.layout();
56278 // ie requires a double layout on the first pass
56279 if(Roo.isIE && !this.initialized){
56280 this.initialized = true;
56281 this.layout.layout();
56286 // activate all subpanels if not currently active..
56288 setActiveState : function(active){
56289 this.active = active;
56291 this.fireEvent("deactivate", this);
56295 this.fireEvent("activate", this);
56296 // not sure if this should happen before or after..
56297 if (!this.layout) {
56298 return; // should not happen..
56301 for (var r in this.layout.regions) {
56302 reg = this.layout.getRegion(r);
56303 if (reg.getActivePanel()) {
56304 //reg.showPanel(reg.getActivePanel()); // force it to activate..
56305 reg.setActivePanel(reg.getActivePanel());
56308 if (!reg.panels.length) {
56311 reg.showPanel(reg.getPanel(0));
56320 * Returns the nested BorderLayout for this panel
56321 * @return {Roo.BorderLayout}
56323 getLayout : function(){
56324 return this.layout;
56328 * Adds a xtype elements to the layout of the nested panel
56332 xtype : 'ContentPanel',
56339 xtype : 'NestedLayoutPanel',
56345 items : [ ... list of content panels or nested layout panels.. ]
56349 * @param {Object} cfg Xtype definition of item to add.
56351 addxtype : function(cfg) {
56352 return this.layout.addxtype(cfg);
56357 Roo.ScrollPanel = function(el, config, content){
56358 config = config || {};
56359 config.fitToFrame = true;
56360 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
56362 this.el.dom.style.overflow = "hidden";
56363 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
56364 this.el.removeClass("x-layout-inactive-content");
56365 this.el.on("mousewheel", this.onWheel, this);
56367 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
56368 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
56369 up.unselectable(); down.unselectable();
56370 up.on("click", this.scrollUp, this);
56371 down.on("click", this.scrollDown, this);
56372 up.addClassOnOver("x-scroller-btn-over");
56373 down.addClassOnOver("x-scroller-btn-over");
56374 up.addClassOnClick("x-scroller-btn-click");
56375 down.addClassOnClick("x-scroller-btn-click");
56376 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
56378 this.resizeEl = this.el;
56379 this.el = wrap; this.up = up; this.down = down;
56382 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
56384 wheelIncrement : 5,
56385 scrollUp : function(){
56386 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
56389 scrollDown : function(){
56390 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
56393 afterScroll : function(){
56394 var el = this.resizeEl;
56395 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
56396 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
56397 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
56400 setSize : function(){
56401 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
56402 this.afterScroll();
56405 onWheel : function(e){
56406 var d = e.getWheelDelta();
56407 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
56408 this.afterScroll();
56412 setContent : function(content, loadScripts){
56413 this.resizeEl.update(content, loadScripts);
56421 * @class Roo.TreePanel
56422 * @extends Roo.ContentPanel
56423 * Treepanel component
56426 * Create a new TreePanel. - defaults to fit/scoll contents.
56427 * @param {String/Object} config A string to set only the panel's title, or a config object
56429 Roo.TreePanel = function(config){
56430 var el = config.el;
56431 var tree = config.tree;
56432 delete config.tree;
56433 delete config.el; // hopefull!
56435 // wrapper for IE7 strict & safari scroll issue
56437 var treeEl = el.createChild();
56438 config.resizeEl = treeEl;
56442 Roo.TreePanel.superclass.constructor.call(this, el, config);
56445 this.tree = new Roo.tree.TreePanel(treeEl , tree);
56446 //console.log(tree);
56447 this.on('activate', function()
56449 if (this.tree.rendered) {
56452 //console.log('render tree');
56453 this.tree.render();
56455 // this should not be needed.. - it's actually the 'el' that resizes?
56456 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
56458 //this.on('resize', function (cp, w, h) {
56459 // this.tree.innerCt.setWidth(w);
56460 // this.tree.innerCt.setHeight(h);
56461 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
56468 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
56472 * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
56490 * Ext JS Library 1.1.1
56491 * Copyright(c) 2006-2007, Ext JS, LLC.
56493 * Originally Released Under LGPL - original licence link has changed is not relivant.
56496 * <script type="text/javascript">
56501 * @class Roo.ReaderLayout
56502 * @extends Roo.BorderLayout
56503 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
56504 * center region containing two nested regions (a top one for a list view and one for item preview below),
56505 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
56506 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
56507 * expedites the setup of the overall layout and regions for this common application style.
56510 var reader = new Roo.ReaderLayout();
56511 var CP = Roo.ContentPanel; // shortcut for adding
56513 reader.beginUpdate();
56514 reader.add("north", new CP("north", "North"));
56515 reader.add("west", new CP("west", {title: "West"}));
56516 reader.add("east", new CP("east", {title: "East"}));
56518 reader.regions.listView.add(new CP("listView", "List"));
56519 reader.regions.preview.add(new CP("preview", "Preview"));
56520 reader.endUpdate();
56523 * Create a new ReaderLayout
56524 * @param {Object} config Configuration options
56525 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
56526 * document.body if omitted)
56528 Roo.ReaderLayout = function(config, renderTo){
56529 var c = config || {size:{}};
56530 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
56531 north: c.north !== false ? Roo.apply({
56535 }, c.north) : false,
56536 west: c.west !== false ? Roo.apply({
56544 margins:{left:5,right:0,bottom:5,top:5},
56545 cmargins:{left:5,right:5,bottom:5,top:5}
56546 }, c.west) : false,
56547 east: c.east !== false ? Roo.apply({
56555 margins:{left:0,right:5,bottom:5,top:5},
56556 cmargins:{left:5,right:5,bottom:5,top:5}
56557 }, c.east) : false,
56558 center: Roo.apply({
56559 tabPosition: 'top',
56563 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
56567 this.el.addClass('x-reader');
56569 this.beginUpdate();
56571 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
56572 south: c.preview !== false ? Roo.apply({
56579 cmargins:{top:5,left:0, right:0, bottom:0}
56580 }, c.preview) : false,
56581 center: Roo.apply({
56587 this.add('center', new Roo.NestedLayoutPanel(inner,
56588 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
56592 this.regions.preview = inner.getRegion('south');
56593 this.regions.listView = inner.getRegion('center');
56596 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
56598 * Ext JS Library 1.1.1
56599 * Copyright(c) 2006-2007, Ext JS, LLC.
56601 * Originally Released Under LGPL - original licence link has changed is not relivant.
56604 * <script type="text/javascript">
56608 * @class Roo.grid.Grid
56609 * @extends Roo.util.Observable
56610 * This class represents the primary interface of a component based grid control.
56611 * <br><br>Usage:<pre><code>
56612 var grid = new Roo.grid.Grid("my-container-id", {
56615 selModel: mySelectionModel,
56616 autoSizeColumns: true,
56617 monitorWindowResize: false,
56618 trackMouseOver: true
56623 * <b>Common Problems:</b><br/>
56624 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
56625 * element will correct this<br/>
56626 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
56627 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
56628 * are unpredictable.<br/>
56629 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
56630 * grid to calculate dimensions/offsets.<br/>
56632 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56633 * The container MUST have some type of size defined for the grid to fill. The container will be
56634 * automatically set to position relative if it isn't already.
56635 * @param {Object} config A config object that sets properties on this grid.
56637 Roo.grid.Grid = function(container, config){
56638 // initialize the container
56639 this.container = Roo.get(container);
56640 this.container.update("");
56641 this.container.setStyle("overflow", "hidden");
56642 this.container.addClass('x-grid-container');
56644 this.id = this.container.id;
56646 Roo.apply(this, config);
56647 // check and correct shorthanded configs
56649 this.dataSource = this.ds;
56653 this.colModel = this.cm;
56657 this.selModel = this.sm;
56661 if (this.selModel) {
56662 this.selModel = Roo.factory(this.selModel, Roo.grid);
56663 this.sm = this.selModel;
56664 this.sm.xmodule = this.xmodule || false;
56666 if (typeof(this.colModel.config) == 'undefined') {
56667 this.colModel = new Roo.grid.ColumnModel(this.colModel);
56668 this.cm = this.colModel;
56669 this.cm.xmodule = this.xmodule || false;
56671 if (this.dataSource) {
56672 this.dataSource= Roo.factory(this.dataSource, Roo.data);
56673 this.ds = this.dataSource;
56674 this.ds.xmodule = this.xmodule || false;
56681 this.container.setWidth(this.width);
56685 this.container.setHeight(this.height);
56692 * The raw click event for the entire grid.
56693 * @param {Roo.EventObject} e
56698 * The raw dblclick event for the entire grid.
56699 * @param {Roo.EventObject} e
56703 * @event contextmenu
56704 * The raw contextmenu event for the entire grid.
56705 * @param {Roo.EventObject} e
56707 "contextmenu" : true,
56710 * The raw mousedown event for the entire grid.
56711 * @param {Roo.EventObject} e
56713 "mousedown" : true,
56716 * The raw mouseup event for the entire grid.
56717 * @param {Roo.EventObject} e
56722 * The raw mouseover event for the entire grid.
56723 * @param {Roo.EventObject} e
56725 "mouseover" : true,
56728 * The raw mouseout event for the entire grid.
56729 * @param {Roo.EventObject} e
56734 * The raw keypress event for the entire grid.
56735 * @param {Roo.EventObject} e
56740 * The raw keydown event for the entire grid.
56741 * @param {Roo.EventObject} e
56749 * Fires when a cell is clicked
56750 * @param {Grid} this
56751 * @param {Number} rowIndex
56752 * @param {Number} columnIndex
56753 * @param {Roo.EventObject} e
56755 "cellclick" : true,
56757 * @event celldblclick
56758 * Fires when a cell is double clicked
56759 * @param {Grid} this
56760 * @param {Number} rowIndex
56761 * @param {Number} columnIndex
56762 * @param {Roo.EventObject} e
56764 "celldblclick" : true,
56767 * Fires when a row is clicked
56768 * @param {Grid} this
56769 * @param {Number} rowIndex
56770 * @param {Roo.EventObject} e
56774 * @event rowdblclick
56775 * Fires when a row is double clicked
56776 * @param {Grid} this
56777 * @param {Number} rowIndex
56778 * @param {Roo.EventObject} e
56780 "rowdblclick" : true,
56782 * @event headerclick
56783 * Fires when a header is clicked
56784 * @param {Grid} this
56785 * @param {Number} columnIndex
56786 * @param {Roo.EventObject} e
56788 "headerclick" : true,
56790 * @event headerdblclick
56791 * Fires when a header cell is double clicked
56792 * @param {Grid} this
56793 * @param {Number} columnIndex
56794 * @param {Roo.EventObject} e
56796 "headerdblclick" : true,
56798 * @event rowcontextmenu
56799 * Fires when a row is right clicked
56800 * @param {Grid} this
56801 * @param {Number} rowIndex
56802 * @param {Roo.EventObject} e
56804 "rowcontextmenu" : true,
56806 * @event cellcontextmenu
56807 * Fires when a cell is right clicked
56808 * @param {Grid} this
56809 * @param {Number} rowIndex
56810 * @param {Number} cellIndex
56811 * @param {Roo.EventObject} e
56813 "cellcontextmenu" : true,
56815 * @event headercontextmenu
56816 * Fires when a header is right clicked
56817 * @param {Grid} this
56818 * @param {Number} columnIndex
56819 * @param {Roo.EventObject} e
56821 "headercontextmenu" : true,
56823 * @event bodyscroll
56824 * Fires when the body element is scrolled
56825 * @param {Number} scrollLeft
56826 * @param {Number} scrollTop
56828 "bodyscroll" : true,
56830 * @event columnresize
56831 * Fires when the user resizes a column
56832 * @param {Number} columnIndex
56833 * @param {Number} newSize
56835 "columnresize" : true,
56837 * @event columnmove
56838 * Fires when the user moves a column
56839 * @param {Number} oldIndex
56840 * @param {Number} newIndex
56842 "columnmove" : true,
56845 * Fires when row(s) start being dragged
56846 * @param {Grid} this
56847 * @param {Roo.GridDD} dd The drag drop object
56848 * @param {event} e The raw browser event
56850 "startdrag" : true,
56853 * Fires when a drag operation is complete
56854 * @param {Grid} this
56855 * @param {Roo.GridDD} dd The drag drop object
56856 * @param {event} e The raw browser event
56861 * Fires when dragged row(s) are dropped on a valid DD target
56862 * @param {Grid} this
56863 * @param {Roo.GridDD} dd The drag drop object
56864 * @param {String} targetId The target drag drop object
56865 * @param {event} e The raw browser event
56870 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56871 * @param {Grid} this
56872 * @param {Roo.GridDD} dd The drag drop object
56873 * @param {String} targetId The target drag drop object
56874 * @param {event} e The raw browser event
56879 * Fires when the dragged row(s) first cross another DD target while being dragged
56880 * @param {Grid} this
56881 * @param {Roo.GridDD} dd The drag drop object
56882 * @param {String} targetId The target drag drop object
56883 * @param {event} e The raw browser event
56885 "dragenter" : true,
56888 * Fires when the dragged row(s) leave another DD target while being dragged
56889 * @param {Grid} this
56890 * @param {Roo.GridDD} dd The drag drop object
56891 * @param {String} targetId The target drag drop object
56892 * @param {event} e The raw browser event
56897 * Fires when a row is rendered, so you can change add a style to it.
56898 * @param {GridView} gridview The grid view
56899 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56905 * Fires when the grid is rendered
56906 * @param {Grid} grid
56911 Roo.grid.Grid.superclass.constructor.call(this);
56913 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
56916 * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
56919 * @cfg {Roo.grid.GridView} view The view that renders the grid (default = Roo.grid.GridView)
56922 * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
56925 * @cfg {Roo.grid.Store} ds The data store for the grid
56928 * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
56931 * @cfg {String} ddGroup - drag drop group.
56934 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
56938 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
56940 minColumnWidth : 25,
56943 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
56944 * <b>on initial render.</b> It is more efficient to explicitly size the columns
56945 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
56947 autoSizeColumns : false,
56950 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
56952 autoSizeHeaders : true,
56955 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
56957 monitorWindowResize : true,
56960 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
56961 * rows measured to get a columns size. Default is 0 (all rows).
56963 maxRowsToMeasure : 0,
56966 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
56968 trackMouseOver : true,
56971 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
56974 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
56978 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
56980 enableDragDrop : false,
56983 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
56985 enableColumnMove : true,
56988 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
56990 enableColumnHide : true,
56993 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
56995 enableRowHeightSync : false,
56998 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
57003 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
57005 autoHeight : false,
57008 * @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.
57010 autoExpandColumn : false,
57013 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
57016 autoExpandMin : 50,
57019 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
57021 autoExpandMax : 1000,
57024 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
57029 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
57033 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
57043 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
57044 * of a fixed width. Default is false.
57047 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
57052 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
57053 * %0 is replaced with the number of selected rows.
57055 ddText : "{0} selected row{1}",
57059 * Called once after all setup has been completed and the grid is ready to be rendered.
57060 * @return {Roo.grid.Grid} this
57062 render : function()
57064 var c = this.container;
57065 // try to detect autoHeight/width mode
57066 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
57067 this.autoHeight = true;
57069 var view = this.getView();
57072 c.on("click", this.onClick, this);
57073 c.on("dblclick", this.onDblClick, this);
57074 c.on("contextmenu", this.onContextMenu, this);
57075 c.on("keydown", this.onKeyDown, this);
57077 c.on("touchstart", this.onTouchStart, this);
57080 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
57082 this.getSelectionModel().init(this);
57087 this.loadMask = new Roo.LoadMask(this.container,
57088 Roo.apply({store:this.dataSource}, this.loadMask));
57092 if (this.toolbar && this.toolbar.xtype) {
57093 this.toolbar.container = this.getView().getHeaderPanel(true);
57094 this.toolbar = new Roo.Toolbar(this.toolbar);
57096 if (this.footer && this.footer.xtype) {
57097 this.footer.dataSource = this.getDataSource();
57098 this.footer.container = this.getView().getFooterPanel(true);
57099 this.footer = Roo.factory(this.footer, Roo);
57101 if (this.dropTarget && this.dropTarget.xtype) {
57102 delete this.dropTarget.xtype;
57103 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
57107 this.rendered = true;
57108 this.fireEvent('render', this);
57113 * Reconfigures the grid to use a different Store and Column Model.
57114 * The View will be bound to the new objects and refreshed.
57115 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
57116 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
57118 reconfigure : function(dataSource, colModel){
57120 this.loadMask.destroy();
57121 this.loadMask = new Roo.LoadMask(this.container,
57122 Roo.apply({store:dataSource}, this.loadMask));
57124 this.view.bind(dataSource, colModel);
57125 this.dataSource = dataSource;
57126 this.colModel = colModel;
57127 this.view.refresh(true);
57131 * Add's a column, default at the end..
57133 * @param {int} position to add (default end)
57134 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
57136 addColumns : function(pos, ar)
57139 for (var i =0;i< ar.length;i++) {
57141 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
57142 this.cm.lookup[cfg.id] = cfg;
57146 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
57147 pos = this.cm.config.length; //this.cm.config.push(cfg);
57149 pos = Math.max(0,pos);
57152 this.cm.config.splice.apply(this.cm.config, ar);
57156 this.view.generateRules(this.cm);
57157 this.view.refresh(true);
57165 onKeyDown : function(e){
57166 this.fireEvent("keydown", e);
57170 * Destroy this grid.
57171 * @param {Boolean} removeEl True to remove the element
57173 destroy : function(removeEl, keepListeners){
57175 this.loadMask.destroy();
57177 var c = this.container;
57178 c.removeAllListeners();
57179 this.view.destroy();
57180 this.colModel.purgeListeners();
57181 if(!keepListeners){
57182 this.purgeListeners();
57185 if(removeEl === true){
57191 processEvent : function(name, e){
57192 // does this fire select???
57193 //Roo.log('grid:processEvent ' + name);
57195 if (name != 'touchstart' ) {
57196 this.fireEvent(name, e);
57199 var t = e.getTarget();
57201 var header = v.findHeaderIndex(t);
57202 if(header !== false){
57203 var ename = name == 'touchstart' ? 'click' : name;
57205 this.fireEvent("header" + ename, this, header, e);
57207 var row = v.findRowIndex(t);
57208 var cell = v.findCellIndex(t);
57209 if (name == 'touchstart') {
57210 // first touch is always a click.
57211 // hopefull this happens after selection is updated.?
57214 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
57215 var cs = this.selModel.getSelectedCell();
57216 if (row == cs[0] && cell == cs[1]){
57220 if (typeof(this.selModel.getSelections) != 'undefined') {
57221 var cs = this.selModel.getSelections();
57222 var ds = this.dataSource;
57223 if (cs.length == 1 && ds.getAt(row) == cs[0]){
57234 this.fireEvent("row" + name, this, row, e);
57235 if(cell !== false){
57236 this.fireEvent("cell" + name, this, row, cell, e);
57243 onClick : function(e){
57244 this.processEvent("click", e);
57247 onTouchStart : function(e){
57248 this.processEvent("touchstart", e);
57252 onContextMenu : function(e, t){
57253 this.processEvent("contextmenu", e);
57257 onDblClick : function(e){
57258 this.processEvent("dblclick", e);
57262 walkCells : function(row, col, step, fn, scope){
57263 var cm = this.colModel, clen = cm.getColumnCount();
57264 var ds = this.dataSource, rlen = ds.getCount(), first = true;
57276 if(fn.call(scope || this, row, col, cm) === true){
57294 if(fn.call(scope || this, row, col, cm) === true){
57306 getSelections : function(){
57307 return this.selModel.getSelections();
57311 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
57312 * but if manual update is required this method will initiate it.
57314 autoSize : function(){
57316 this.view.layout();
57317 if(this.view.adjustForScroll){
57318 this.view.adjustForScroll();
57324 * Returns the grid's underlying element.
57325 * @return {Element} The element
57327 getGridEl : function(){
57328 return this.container;
57331 // private for compatibility, overridden by editor grid
57332 stopEditing : function(){},
57335 * Returns the grid's SelectionModel.
57336 * @return {SelectionModel}
57338 getSelectionModel : function(){
57339 if(!this.selModel){
57340 this.selModel = new Roo.grid.RowSelectionModel();
57342 return this.selModel;
57346 * Returns the grid's DataSource.
57347 * @return {DataSource}
57349 getDataSource : function(){
57350 return this.dataSource;
57354 * Returns the grid's ColumnModel.
57355 * @return {ColumnModel}
57357 getColumnModel : function(){
57358 return this.colModel;
57362 * Returns the grid's GridView object.
57363 * @return {GridView}
57365 getView : function(){
57367 this.view = new Roo.grid.GridView(this.viewConfig);
57368 this.relayEvents(this.view, [
57369 "beforerowremoved", "beforerowsinserted",
57370 "beforerefresh", "rowremoved",
57371 "rowsinserted", "rowupdated" ,"refresh"
57377 * Called to get grid's drag proxy text, by default returns this.ddText.
57378 * Override this to put something different in the dragged text.
57381 getDragDropText : function(){
57382 var count = this.selModel.getCount();
57383 return String.format(this.ddText, count, count == 1 ? '' : 's');
57388 * Ext JS Library 1.1.1
57389 * Copyright(c) 2006-2007, Ext JS, LLC.
57391 * Originally Released Under LGPL - original licence link has changed is not relivant.
57394 * <script type="text/javascript">
57397 * @class Roo.grid.AbstractGridView
57398 * @extends Roo.util.Observable
57400 * Abstract base class for grid Views
57403 Roo.grid.AbstractGridView = function(){
57407 "beforerowremoved" : true,
57408 "beforerowsinserted" : true,
57409 "beforerefresh" : true,
57410 "rowremoved" : true,
57411 "rowsinserted" : true,
57412 "rowupdated" : true,
57415 Roo.grid.AbstractGridView.superclass.constructor.call(this);
57418 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
57419 rowClass : "x-grid-row",
57420 cellClass : "x-grid-cell",
57421 tdClass : "x-grid-td",
57422 hdClass : "x-grid-hd",
57423 splitClass : "x-grid-hd-split",
57425 init: function(grid){
57427 var cid = this.grid.getGridEl().id;
57428 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
57429 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
57430 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
57431 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
57434 getColumnRenderers : function(){
57435 var renderers = [];
57436 var cm = this.grid.colModel;
57437 var colCount = cm.getColumnCount();
57438 for(var i = 0; i < colCount; i++){
57439 renderers[i] = cm.getRenderer(i);
57444 getColumnIds : function(){
57446 var cm = this.grid.colModel;
57447 var colCount = cm.getColumnCount();
57448 for(var i = 0; i < colCount; i++){
57449 ids[i] = cm.getColumnId(i);
57454 getDataIndexes : function(){
57455 if(!this.indexMap){
57456 this.indexMap = this.buildIndexMap();
57458 return this.indexMap.colToData;
57461 getColumnIndexByDataIndex : function(dataIndex){
57462 if(!this.indexMap){
57463 this.indexMap = this.buildIndexMap();
57465 return this.indexMap.dataToCol[dataIndex];
57469 * Set a css style for a column dynamically.
57470 * @param {Number} colIndex The index of the column
57471 * @param {String} name The css property name
57472 * @param {String} value The css value
57474 setCSSStyle : function(colIndex, name, value){
57475 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
57476 Roo.util.CSS.updateRule(selector, name, value);
57479 generateRules : function(cm){
57480 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
57481 Roo.util.CSS.removeStyleSheet(rulesId);
57482 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57483 var cid = cm.getColumnId(i);
57484 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
57485 this.tdSelector, cid, " {\n}\n",
57486 this.hdSelector, cid, " {\n}\n",
57487 this.splitSelector, cid, " {\n}\n");
57489 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
57493 * Ext JS Library 1.1.1
57494 * Copyright(c) 2006-2007, Ext JS, LLC.
57496 * Originally Released Under LGPL - original licence link has changed is not relivant.
57499 * <script type="text/javascript">
57503 // This is a support class used internally by the Grid components
57504 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
57506 this.view = grid.getView();
57507 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
57508 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
57510 this.setHandleElId(Roo.id(hd));
57511 this.setOuterHandleElId(Roo.id(hd2));
57513 this.scroll = false;
57515 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
57517 getDragData : function(e){
57518 var t = Roo.lib.Event.getTarget(e);
57519 var h = this.view.findHeaderCell(t);
57521 return {ddel: h.firstChild, header:h};
57526 onInitDrag : function(e){
57527 this.view.headersDisabled = true;
57528 var clone = this.dragData.ddel.cloneNode(true);
57529 clone.id = Roo.id();
57530 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
57531 this.proxy.update(clone);
57535 afterValidDrop : function(){
57537 setTimeout(function(){
57538 v.headersDisabled = false;
57542 afterInvalidDrop : function(){
57544 setTimeout(function(){
57545 v.headersDisabled = false;
57551 * Ext JS Library 1.1.1
57552 * Copyright(c) 2006-2007, Ext JS, LLC.
57554 * Originally Released Under LGPL - original licence link has changed is not relivant.
57557 * <script type="text/javascript">
57560 // This is a support class used internally by the Grid components
57561 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
57563 this.view = grid.getView();
57564 // split the proxies so they don't interfere with mouse events
57565 this.proxyTop = Roo.DomHelper.append(document.body, {
57566 cls:"col-move-top", html:" "
57568 this.proxyBottom = Roo.DomHelper.append(document.body, {
57569 cls:"col-move-bottom", html:" "
57571 this.proxyTop.hide = this.proxyBottom.hide = function(){
57572 this.setLeftTop(-100,-100);
57573 this.setStyle("visibility", "hidden");
57575 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
57576 // temporarily disabled
57577 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
57578 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
57580 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
57581 proxyOffsets : [-4, -9],
57582 fly: Roo.Element.fly,
57584 getTargetFromEvent : function(e){
57585 var t = Roo.lib.Event.getTarget(e);
57586 var cindex = this.view.findCellIndex(t);
57587 if(cindex !== false){
57588 return this.view.getHeaderCell(cindex);
57593 nextVisible : function(h){
57594 var v = this.view, cm = this.grid.colModel;
57597 if(!cm.isHidden(v.getCellIndex(h))){
57605 prevVisible : function(h){
57606 var v = this.view, cm = this.grid.colModel;
57609 if(!cm.isHidden(v.getCellIndex(h))){
57617 positionIndicator : function(h, n, e){
57618 var x = Roo.lib.Event.getPageX(e);
57619 var r = Roo.lib.Dom.getRegion(n.firstChild);
57620 var px, pt, py = r.top + this.proxyOffsets[1];
57621 if((r.right - x) <= (r.right-r.left)/2){
57622 px = r.right+this.view.borderWidth;
57628 var oldIndex = this.view.getCellIndex(h);
57629 var newIndex = this.view.getCellIndex(n);
57631 if(this.grid.colModel.isFixed(newIndex)){
57635 var locked = this.grid.colModel.isLocked(newIndex);
57640 if(oldIndex < newIndex){
57643 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
57646 px += this.proxyOffsets[0];
57647 this.proxyTop.setLeftTop(px, py);
57648 this.proxyTop.show();
57649 if(!this.bottomOffset){
57650 this.bottomOffset = this.view.mainHd.getHeight();
57652 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
57653 this.proxyBottom.show();
57657 onNodeEnter : function(n, dd, e, data){
57658 if(data.header != n){
57659 this.positionIndicator(data.header, n, e);
57663 onNodeOver : function(n, dd, e, data){
57664 var result = false;
57665 if(data.header != n){
57666 result = this.positionIndicator(data.header, n, e);
57669 this.proxyTop.hide();
57670 this.proxyBottom.hide();
57672 return result ? this.dropAllowed : this.dropNotAllowed;
57675 onNodeOut : function(n, dd, e, data){
57676 this.proxyTop.hide();
57677 this.proxyBottom.hide();
57680 onNodeDrop : function(n, dd, e, data){
57681 var h = data.header;
57683 var cm = this.grid.colModel;
57684 var x = Roo.lib.Event.getPageX(e);
57685 var r = Roo.lib.Dom.getRegion(n.firstChild);
57686 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
57687 var oldIndex = this.view.getCellIndex(h);
57688 var newIndex = this.view.getCellIndex(n);
57689 var locked = cm.isLocked(newIndex);
57693 if(oldIndex < newIndex){
57696 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
57699 cm.setLocked(oldIndex, locked, true);
57700 cm.moveColumn(oldIndex, newIndex);
57701 this.grid.fireEvent("columnmove", oldIndex, newIndex);
57709 * Ext JS Library 1.1.1
57710 * Copyright(c) 2006-2007, Ext JS, LLC.
57712 * Originally Released Under LGPL - original licence link has changed is not relivant.
57715 * <script type="text/javascript">
57719 * @class Roo.grid.GridView
57720 * @extends Roo.util.Observable
57723 * @param {Object} config
57725 Roo.grid.GridView = function(config){
57726 Roo.grid.GridView.superclass.constructor.call(this);
57729 Roo.apply(this, config);
57732 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
57734 unselectable : 'unselectable="on"',
57735 unselectableCls : 'x-unselectable',
57738 rowClass : "x-grid-row",
57740 cellClass : "x-grid-col",
57742 tdClass : "x-grid-td",
57744 hdClass : "x-grid-hd",
57746 splitClass : "x-grid-split",
57748 sortClasses : ["sort-asc", "sort-desc"],
57750 enableMoveAnim : false,
57754 dh : Roo.DomHelper,
57756 fly : Roo.Element.fly,
57758 css : Roo.util.CSS,
57764 scrollIncrement : 22,
57766 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
57768 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
57770 bind : function(ds, cm){
57772 this.ds.un("load", this.onLoad, this);
57773 this.ds.un("datachanged", this.onDataChange, this);
57774 this.ds.un("add", this.onAdd, this);
57775 this.ds.un("remove", this.onRemove, this);
57776 this.ds.un("update", this.onUpdate, this);
57777 this.ds.un("clear", this.onClear, this);
57780 ds.on("load", this.onLoad, this);
57781 ds.on("datachanged", this.onDataChange, this);
57782 ds.on("add", this.onAdd, this);
57783 ds.on("remove", this.onRemove, this);
57784 ds.on("update", this.onUpdate, this);
57785 ds.on("clear", this.onClear, this);
57790 this.cm.un("widthchange", this.onColWidthChange, this);
57791 this.cm.un("headerchange", this.onHeaderChange, this);
57792 this.cm.un("hiddenchange", this.onHiddenChange, this);
57793 this.cm.un("columnmoved", this.onColumnMove, this);
57794 this.cm.un("columnlockchange", this.onColumnLock, this);
57797 this.generateRules(cm);
57798 cm.on("widthchange", this.onColWidthChange, this);
57799 cm.on("headerchange", this.onHeaderChange, this);
57800 cm.on("hiddenchange", this.onHiddenChange, this);
57801 cm.on("columnmoved", this.onColumnMove, this);
57802 cm.on("columnlockchange", this.onColumnLock, this);
57807 init: function(grid){
57808 Roo.grid.GridView.superclass.init.call(this, grid);
57810 this.bind(grid.dataSource, grid.colModel);
57812 grid.on("headerclick", this.handleHeaderClick, this);
57814 if(grid.trackMouseOver){
57815 grid.on("mouseover", this.onRowOver, this);
57816 grid.on("mouseout", this.onRowOut, this);
57818 grid.cancelTextSelection = function(){};
57819 this.gridId = grid.id;
57821 var tpls = this.templates || {};
57824 tpls.master = new Roo.Template(
57825 '<div class="x-grid" hidefocus="true">',
57826 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
57827 '<div class="x-grid-topbar"></div>',
57828 '<div class="x-grid-scroller"><div></div></div>',
57829 '<div class="x-grid-locked">',
57830 '<div class="x-grid-header">{lockedHeader}</div>',
57831 '<div class="x-grid-body">{lockedBody}</div>',
57833 '<div class="x-grid-viewport">',
57834 '<div class="x-grid-header">{header}</div>',
57835 '<div class="x-grid-body">{body}</div>',
57837 '<div class="x-grid-bottombar"></div>',
57839 '<div class="x-grid-resize-proxy"> </div>',
57842 tpls.master.disableformats = true;
57846 tpls.header = new Roo.Template(
57847 '<table border="0" cellspacing="0" cellpadding="0">',
57848 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
57851 tpls.header.disableformats = true;
57853 tpls.header.compile();
57856 tpls.hcell = new Roo.Template(
57857 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
57858 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
57861 tpls.hcell.disableFormats = true;
57863 tpls.hcell.compile();
57866 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
57867 this.unselectableCls + '" ' + this.unselectable +'> </div>');
57868 tpls.hsplit.disableFormats = true;
57870 tpls.hsplit.compile();
57873 tpls.body = new Roo.Template(
57874 '<table border="0" cellspacing="0" cellpadding="0">',
57875 "<tbody>{rows}</tbody>",
57878 tpls.body.disableFormats = true;
57880 tpls.body.compile();
57883 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
57884 tpls.row.disableFormats = true;
57886 tpls.row.compile();
57889 tpls.cell = new Roo.Template(
57890 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
57891 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
57892 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
57895 tpls.cell.disableFormats = true;
57897 tpls.cell.compile();
57899 this.templates = tpls;
57902 // remap these for backwards compat
57903 onColWidthChange : function(){
57904 this.updateColumns.apply(this, arguments);
57906 onHeaderChange : function(){
57907 this.updateHeaders.apply(this, arguments);
57909 onHiddenChange : function(){
57910 this.handleHiddenChange.apply(this, arguments);
57912 onColumnMove : function(){
57913 this.handleColumnMove.apply(this, arguments);
57915 onColumnLock : function(){
57916 this.handleLockChange.apply(this, arguments);
57919 onDataChange : function(){
57921 this.updateHeaderSortState();
57924 onClear : function(){
57928 onUpdate : function(ds, record){
57929 this.refreshRow(record);
57932 refreshRow : function(record){
57933 var ds = this.ds, index;
57934 if(typeof record == 'number'){
57936 record = ds.getAt(index);
57938 index = ds.indexOf(record);
57940 this.insertRows(ds, index, index, true);
57941 this.onRemove(ds, record, index+1, true);
57942 this.syncRowHeights(index, index);
57944 this.fireEvent("rowupdated", this, index, record);
57947 onAdd : function(ds, records, index){
57948 this.insertRows(ds, index, index + (records.length-1));
57951 onRemove : function(ds, record, index, isUpdate){
57952 if(isUpdate !== true){
57953 this.fireEvent("beforerowremoved", this, index, record);
57955 var bt = this.getBodyTable(), lt = this.getLockedTable();
57956 if(bt.rows[index]){
57957 bt.firstChild.removeChild(bt.rows[index]);
57959 if(lt.rows[index]){
57960 lt.firstChild.removeChild(lt.rows[index]);
57962 if(isUpdate !== true){
57963 this.stripeRows(index);
57964 this.syncRowHeights(index, index);
57966 this.fireEvent("rowremoved", this, index, record);
57970 onLoad : function(){
57971 this.scrollToTop();
57975 * Scrolls the grid to the top
57977 scrollToTop : function(){
57979 this.scroller.dom.scrollTop = 0;
57985 * Gets a panel in the header of the grid that can be used for toolbars etc.
57986 * After modifying the contents of this panel a call to grid.autoSize() may be
57987 * required to register any changes in size.
57988 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
57989 * @return Roo.Element
57991 getHeaderPanel : function(doShow){
57993 this.headerPanel.show();
57995 return this.headerPanel;
57999 * Gets a panel in the footer of the grid that can be used for toolbars etc.
58000 * After modifying the contents of this panel a call to grid.autoSize() may be
58001 * required to register any changes in size.
58002 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
58003 * @return Roo.Element
58005 getFooterPanel : function(doShow){
58007 this.footerPanel.show();
58009 return this.footerPanel;
58012 initElements : function(){
58013 var E = Roo.Element;
58014 var el = this.grid.getGridEl().dom.firstChild;
58015 var cs = el.childNodes;
58017 this.el = new E(el);
58019 this.focusEl = new E(el.firstChild);
58020 this.focusEl.swallowEvent("click", true);
58022 this.headerPanel = new E(cs[1]);
58023 this.headerPanel.enableDisplayMode("block");
58025 this.scroller = new E(cs[2]);
58026 this.scrollSizer = new E(this.scroller.dom.firstChild);
58028 this.lockedWrap = new E(cs[3]);
58029 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
58030 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
58032 this.mainWrap = new E(cs[4]);
58033 this.mainHd = new E(this.mainWrap.dom.firstChild);
58034 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
58036 this.footerPanel = new E(cs[5]);
58037 this.footerPanel.enableDisplayMode("block");
58039 this.resizeProxy = new E(cs[6]);
58041 this.headerSelector = String.format(
58042 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
58043 this.lockedHd.id, this.mainHd.id
58046 this.splitterSelector = String.format(
58047 '#{0} div.x-grid-split, #{1} div.x-grid-split',
58048 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
58051 idToCssName : function(s)
58053 return s.replace(/[^a-z0-9]+/ig, '-');
58056 getHeaderCell : function(index){
58057 return Roo.DomQuery.select(this.headerSelector)[index];
58060 getHeaderCellMeasure : function(index){
58061 return this.getHeaderCell(index).firstChild;
58064 getHeaderCellText : function(index){
58065 return this.getHeaderCell(index).firstChild.firstChild;
58068 getLockedTable : function(){
58069 return this.lockedBody.dom.firstChild;
58072 getBodyTable : function(){
58073 return this.mainBody.dom.firstChild;
58076 getLockedRow : function(index){
58077 return this.getLockedTable().rows[index];
58080 getRow : function(index){
58081 return this.getBodyTable().rows[index];
58084 getRowComposite : function(index){
58086 this.rowEl = new Roo.CompositeElementLite();
58088 var els = [], lrow, mrow;
58089 if(lrow = this.getLockedRow(index)){
58092 if(mrow = this.getRow(index)){
58095 this.rowEl.elements = els;
58099 * Gets the 'td' of the cell
58101 * @param {Integer} rowIndex row to select
58102 * @param {Integer} colIndex column to select
58106 getCell : function(rowIndex, colIndex){
58107 var locked = this.cm.getLockedCount();
58109 if(colIndex < locked){
58110 source = this.lockedBody.dom.firstChild;
58112 source = this.mainBody.dom.firstChild;
58113 colIndex -= locked;
58115 return source.rows[rowIndex].childNodes[colIndex];
58118 getCellText : function(rowIndex, colIndex){
58119 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
58122 getCellBox : function(cell){
58123 var b = this.fly(cell).getBox();
58124 if(Roo.isOpera){ // opera fails to report the Y
58125 b.y = cell.offsetTop + this.mainBody.getY();
58130 getCellIndex : function(cell){
58131 var id = String(cell.className).match(this.cellRE);
58133 return parseInt(id[1], 10);
58138 findHeaderIndex : function(n){
58139 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
58140 return r ? this.getCellIndex(r) : false;
58143 findHeaderCell : function(n){
58144 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
58145 return r ? r : false;
58148 findRowIndex : function(n){
58152 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
58153 return r ? r.rowIndex : false;
58156 findCellIndex : function(node){
58157 var stop = this.el.dom;
58158 while(node && node != stop){
58159 if(this.findRE.test(node.className)){
58160 return this.getCellIndex(node);
58162 node = node.parentNode;
58167 getColumnId : function(index){
58168 return this.cm.getColumnId(index);
58171 getSplitters : function()
58173 if(this.splitterSelector){
58174 return Roo.DomQuery.select(this.splitterSelector);
58180 getSplitter : function(index){
58181 return this.getSplitters()[index];
58184 onRowOver : function(e, t){
58186 if((row = this.findRowIndex(t)) !== false){
58187 this.getRowComposite(row).addClass("x-grid-row-over");
58191 onRowOut : function(e, t){
58193 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
58194 this.getRowComposite(row).removeClass("x-grid-row-over");
58198 renderHeaders : function(){
58200 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
58201 var cb = [], lb = [], sb = [], lsb = [], p = {};
58202 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58203 p.cellId = "x-grid-hd-0-" + i;
58204 p.splitId = "x-grid-csplit-0-" + i;
58205 p.id = cm.getColumnId(i);
58206 p.value = cm.getColumnHeader(i) || "";
58207 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
58208 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
58209 if(!cm.isLocked(i)){
58210 cb[cb.length] = ct.apply(p);
58211 sb[sb.length] = st.apply(p);
58213 lb[lb.length] = ct.apply(p);
58214 lsb[lsb.length] = st.apply(p);
58217 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
58218 ht.apply({cells: cb.join(""), splits:sb.join("")})];
58221 updateHeaders : function(){
58222 var html = this.renderHeaders();
58223 this.lockedHd.update(html[0]);
58224 this.mainHd.update(html[1]);
58228 * Focuses the specified row.
58229 * @param {Number} row The row index
58231 focusRow : function(row)
58233 //Roo.log('GridView.focusRow');
58234 var x = this.scroller.dom.scrollLeft;
58235 this.focusCell(row, 0, false);
58236 this.scroller.dom.scrollLeft = x;
58240 * Focuses the specified cell.
58241 * @param {Number} row The row index
58242 * @param {Number} col The column index
58243 * @param {Boolean} hscroll false to disable horizontal scrolling
58245 focusCell : function(row, col, hscroll)
58247 //Roo.log('GridView.focusCell');
58248 var el = this.ensureVisible(row, col, hscroll);
58249 this.focusEl.alignTo(el, "tl-tl");
58251 this.focusEl.focus();
58253 this.focusEl.focus.defer(1, this.focusEl);
58258 * Scrolls the specified cell into view
58259 * @param {Number} row The row index
58260 * @param {Number} col The column index
58261 * @param {Boolean} hscroll false to disable horizontal scrolling
58263 ensureVisible : function(row, col, hscroll)
58265 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
58266 //return null; //disable for testing.
58267 if(typeof row != "number"){
58268 row = row.rowIndex;
58270 if(row < 0 && row >= this.ds.getCount()){
58273 col = (col !== undefined ? col : 0);
58274 var cm = this.grid.colModel;
58275 while(cm.isHidden(col)){
58279 var el = this.getCell(row, col);
58283 var c = this.scroller.dom;
58285 var ctop = parseInt(el.offsetTop, 10);
58286 var cleft = parseInt(el.offsetLeft, 10);
58287 var cbot = ctop + el.offsetHeight;
58288 var cright = cleft + el.offsetWidth;
58290 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
58291 var stop = parseInt(c.scrollTop, 10);
58292 var sleft = parseInt(c.scrollLeft, 10);
58293 var sbot = stop + ch;
58294 var sright = sleft + c.clientWidth;
58296 Roo.log('GridView.ensureVisible:' +
58298 ' c.clientHeight:' + c.clientHeight +
58299 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
58307 c.scrollTop = ctop;
58308 //Roo.log("set scrolltop to ctop DISABLE?");
58309 }else if(cbot > sbot){
58310 //Roo.log("set scrolltop to cbot-ch");
58311 c.scrollTop = cbot-ch;
58314 if(hscroll !== false){
58316 c.scrollLeft = cleft;
58317 }else if(cright > sright){
58318 c.scrollLeft = cright-c.clientWidth;
58325 updateColumns : function(){
58326 this.grid.stopEditing();
58327 var cm = this.grid.colModel, colIds = this.getColumnIds();
58328 //var totalWidth = cm.getTotalWidth();
58330 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58331 //if(cm.isHidden(i)) continue;
58332 var w = cm.getColumnWidth(i);
58333 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
58334 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
58336 this.updateSplitters();
58339 generateRules : function(cm){
58340 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
58341 Roo.util.CSS.removeStyleSheet(rulesId);
58342 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58343 var cid = cm.getColumnId(i);
58345 if(cm.config[i].align){
58346 align = 'text-align:'+cm.config[i].align+';';
58349 if(cm.isHidden(i)){
58350 hidden = 'display:none;';
58352 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
58354 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
58355 this.hdSelector, cid, " {\n", align, width, "}\n",
58356 this.tdSelector, cid, " {\n",hidden,"\n}\n",
58357 this.splitSelector, cid, " {\n", hidden , "\n}\n");
58359 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
58362 updateSplitters : function(){
58363 var cm = this.cm, s = this.getSplitters();
58364 if(s){ // splitters not created yet
58365 var pos = 0, locked = true;
58366 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58367 if(cm.isHidden(i)) {
58370 var w = cm.getColumnWidth(i); // make sure it's a number
58371 if(!cm.isLocked(i) && locked){
58376 s[i].style.left = (pos-this.splitOffset) + "px";
58381 handleHiddenChange : function(colModel, colIndex, hidden){
58383 this.hideColumn(colIndex);
58385 this.unhideColumn(colIndex);
58389 hideColumn : function(colIndex){
58390 var cid = this.getColumnId(colIndex);
58391 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
58392 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
58394 this.updateHeaders();
58396 this.updateSplitters();
58400 unhideColumn : function(colIndex){
58401 var cid = this.getColumnId(colIndex);
58402 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
58403 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
58406 this.updateHeaders();
58408 this.updateSplitters();
58412 insertRows : function(dm, firstRow, lastRow, isUpdate){
58413 if(firstRow == 0 && lastRow == dm.getCount()-1){
58417 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
58419 var s = this.getScrollState();
58420 var markup = this.renderRows(firstRow, lastRow);
58421 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
58422 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
58423 this.restoreScroll(s);
58425 this.fireEvent("rowsinserted", this, firstRow, lastRow);
58426 this.syncRowHeights(firstRow, lastRow);
58427 this.stripeRows(firstRow);
58433 bufferRows : function(markup, target, index){
58434 var before = null, trows = target.rows, tbody = target.tBodies[0];
58435 if(index < trows.length){
58436 before = trows[index];
58438 var b = document.createElement("div");
58439 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
58440 var rows = b.firstChild.rows;
58441 for(var i = 0, len = rows.length; i < len; i++){
58443 tbody.insertBefore(rows[0], before);
58445 tbody.appendChild(rows[0]);
58452 deleteRows : function(dm, firstRow, lastRow){
58453 if(dm.getRowCount()<1){
58454 this.fireEvent("beforerefresh", this);
58455 this.mainBody.update("");
58456 this.lockedBody.update("");
58457 this.fireEvent("refresh", this);
58459 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
58460 var bt = this.getBodyTable();
58461 var tbody = bt.firstChild;
58462 var rows = bt.rows;
58463 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
58464 tbody.removeChild(rows[firstRow]);
58466 this.stripeRows(firstRow);
58467 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
58471 updateRows : function(dataSource, firstRow, lastRow){
58472 var s = this.getScrollState();
58474 this.restoreScroll(s);
58477 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
58481 this.updateHeaderSortState();
58484 getScrollState : function(){
58486 var sb = this.scroller.dom;
58487 return {left: sb.scrollLeft, top: sb.scrollTop};
58490 stripeRows : function(startRow){
58491 if(!this.grid.stripeRows || this.ds.getCount() < 1){
58494 startRow = startRow || 0;
58495 var rows = this.getBodyTable().rows;
58496 var lrows = this.getLockedTable().rows;
58497 var cls = ' x-grid-row-alt ';
58498 for(var i = startRow, len = rows.length; i < len; i++){
58499 var row = rows[i], lrow = lrows[i];
58500 var isAlt = ((i+1) % 2 == 0);
58501 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
58502 if(isAlt == hasAlt){
58506 row.className += " x-grid-row-alt";
58508 row.className = row.className.replace("x-grid-row-alt", "");
58511 lrow.className = row.className;
58516 restoreScroll : function(state){
58517 //Roo.log('GridView.restoreScroll');
58518 var sb = this.scroller.dom;
58519 sb.scrollLeft = state.left;
58520 sb.scrollTop = state.top;
58524 syncScroll : function(){
58525 //Roo.log('GridView.syncScroll');
58526 var sb = this.scroller.dom;
58527 var sh = this.mainHd.dom;
58528 var bs = this.mainBody.dom;
58529 var lv = this.lockedBody.dom;
58530 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
58531 lv.scrollTop = bs.scrollTop = sb.scrollTop;
58534 handleScroll : function(e){
58536 var sb = this.scroller.dom;
58537 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
58541 handleWheel : function(e){
58542 var d = e.getWheelDelta();
58543 this.scroller.dom.scrollTop -= d*22;
58544 // set this here to prevent jumpy scrolling on large tables
58545 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
58549 renderRows : function(startRow, endRow){
58550 // pull in all the crap needed to render rows
58551 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
58552 var colCount = cm.getColumnCount();
58554 if(ds.getCount() < 1){
58558 // build a map for all the columns
58560 for(var i = 0; i < colCount; i++){
58561 var name = cm.getDataIndex(i);
58563 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
58564 renderer : cm.getRenderer(i),
58565 id : cm.getColumnId(i),
58566 locked : cm.isLocked(i),
58567 has_editor : cm.isCellEditable(i)
58571 startRow = startRow || 0;
58572 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
58574 // records to render
58575 var rs = ds.getRange(startRow, endRow);
58577 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
58580 // As much as I hate to duplicate code, this was branched because FireFox really hates
58581 // [].join("") on strings. The performance difference was substantial enough to
58582 // branch this function
58583 doRender : Roo.isGecko ?
58584 function(cs, rs, ds, startRow, colCount, stripe){
58585 var ts = this.templates, ct = ts.cell, rt = ts.row;
58587 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
58589 var hasListener = this.grid.hasListener('rowclass');
58591 for(var j = 0, len = rs.length; j < len; j++){
58592 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
58593 for(var i = 0; i < colCount; i++){
58595 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
58597 p.css = p.attr = "";
58598 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
58599 if(p.value == undefined || p.value === "") {
58600 p.value = " ";
58603 p.css += ' x-grid-editable-cell';
58605 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
58606 p.css += ' x-grid-dirty-cell';
58608 var markup = ct.apply(p);
58616 if(stripe && ((rowIndex+1) % 2 == 0)){
58617 alt.push("x-grid-row-alt")
58620 alt.push( " x-grid-dirty-row");
58623 if(this.getRowClass){
58624 alt.push(this.getRowClass(r, rowIndex));
58630 rowIndex : rowIndex,
58633 this.grid.fireEvent('rowclass', this, rowcfg);
58634 alt.push(rowcfg.rowClass);
58636 rp.alt = alt.join(" ");
58637 lbuf+= rt.apply(rp);
58639 buf+= rt.apply(rp);
58641 return [lbuf, buf];
58643 function(cs, rs, ds, startRow, colCount, stripe){
58644 var ts = this.templates, ct = ts.cell, rt = ts.row;
58646 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
58647 var hasListener = this.grid.hasListener('rowclass');
58650 for(var j = 0, len = rs.length; j < len; j++){
58651 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
58652 for(var i = 0; i < colCount; i++){
58654 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
58656 p.css = p.attr = "";
58657 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
58658 if(p.value == undefined || p.value === "") {
58659 p.value = " ";
58663 p.css += ' x-grid-editable-cell';
58665 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
58666 p.css += ' x-grid-dirty-cell'
58669 var markup = ct.apply(p);
58671 cb[cb.length] = markup;
58673 lcb[lcb.length] = markup;
58677 if(stripe && ((rowIndex+1) % 2 == 0)){
58678 alt.push( "x-grid-row-alt");
58681 alt.push(" x-grid-dirty-row");
58684 if(this.getRowClass){
58685 alt.push( this.getRowClass(r, rowIndex));
58691 rowIndex : rowIndex,
58694 this.grid.fireEvent('rowclass', this, rowcfg);
58695 alt.push(rowcfg.rowClass);
58698 rp.alt = alt.join(" ");
58699 rp.cells = lcb.join("");
58700 lbuf[lbuf.length] = rt.apply(rp);
58701 rp.cells = cb.join("");
58702 buf[buf.length] = rt.apply(rp);
58704 return [lbuf.join(""), buf.join("")];
58707 renderBody : function(){
58708 var markup = this.renderRows();
58709 var bt = this.templates.body;
58710 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
58714 * Refreshes the grid
58715 * @param {Boolean} headersToo
58717 refresh : function(headersToo){
58718 this.fireEvent("beforerefresh", this);
58719 this.grid.stopEditing();
58720 var result = this.renderBody();
58721 this.lockedBody.update(result[0]);
58722 this.mainBody.update(result[1]);
58723 if(headersToo === true){
58724 this.updateHeaders();
58725 this.updateColumns();
58726 this.updateSplitters();
58727 this.updateHeaderSortState();
58729 this.syncRowHeights();
58731 this.fireEvent("refresh", this);
58734 handleColumnMove : function(cm, oldIndex, newIndex){
58735 this.indexMap = null;
58736 var s = this.getScrollState();
58737 this.refresh(true);
58738 this.restoreScroll(s);
58739 this.afterMove(newIndex);
58742 afterMove : function(colIndex){
58743 if(this.enableMoveAnim && Roo.enableFx){
58744 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
58746 // if multisort - fix sortOrder, and reload..
58747 if (this.grid.dataSource.multiSort) {
58748 // the we can call sort again..
58749 var dm = this.grid.dataSource;
58750 var cm = this.grid.colModel;
58752 for(var i = 0; i < cm.config.length; i++ ) {
58754 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
58755 continue; // dont' bother, it's not in sort list or being set.
58758 so.push(cm.config[i].dataIndex);
58761 dm.load(dm.lastOptions);
58768 updateCell : function(dm, rowIndex, dataIndex){
58769 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
58770 if(typeof colIndex == "undefined"){ // not present in grid
58773 var cm = this.grid.colModel;
58774 var cell = this.getCell(rowIndex, colIndex);
58775 var cellText = this.getCellText(rowIndex, colIndex);
58778 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
58779 id : cm.getColumnId(colIndex),
58780 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
58782 var renderer = cm.getRenderer(colIndex);
58783 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
58784 if(typeof val == "undefined" || val === "") {
58787 cellText.innerHTML = val;
58788 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
58789 this.syncRowHeights(rowIndex, rowIndex);
58792 calcColumnWidth : function(colIndex, maxRowsToMeasure){
58794 if(this.grid.autoSizeHeaders){
58795 var h = this.getHeaderCellMeasure(colIndex);
58796 maxWidth = Math.max(maxWidth, h.scrollWidth);
58799 if(this.cm.isLocked(colIndex)){
58800 tb = this.getLockedTable();
58803 tb = this.getBodyTable();
58804 index = colIndex - this.cm.getLockedCount();
58807 var rows = tb.rows;
58808 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
58809 for(var i = 0; i < stopIndex; i++){
58810 var cell = rows[i].childNodes[index].firstChild;
58811 maxWidth = Math.max(maxWidth, cell.scrollWidth);
58814 return maxWidth + /*margin for error in IE*/ 5;
58817 * Autofit a column to its content.
58818 * @param {Number} colIndex
58819 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
58821 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
58822 if(this.cm.isHidden(colIndex)){
58823 return; // can't calc a hidden column
58826 var cid = this.cm.getColumnId(colIndex);
58827 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
58828 if(this.grid.autoSizeHeaders){
58829 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
58832 var newWidth = this.calcColumnWidth(colIndex);
58833 this.cm.setColumnWidth(colIndex,
58834 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
58835 if(!suppressEvent){
58836 this.grid.fireEvent("columnresize", colIndex, newWidth);
58841 * Autofits all columns to their content and then expands to fit any extra space in the grid
58843 autoSizeColumns : function(){
58844 var cm = this.grid.colModel;
58845 var colCount = cm.getColumnCount();
58846 for(var i = 0; i < colCount; i++){
58847 this.autoSizeColumn(i, true, true);
58849 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
58852 this.updateColumns();
58858 * Autofits all columns to the grid's width proportionate with their current size
58859 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
58861 fitColumns : function(reserveScrollSpace){
58862 var cm = this.grid.colModel;
58863 var colCount = cm.getColumnCount();
58867 for (i = 0; i < colCount; i++){
58868 if(!cm.isHidden(i) && !cm.isFixed(i)){
58869 w = cm.getColumnWidth(i);
58875 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
58876 if(reserveScrollSpace){
58879 var frac = (avail - cm.getTotalWidth())/width;
58880 while (cols.length){
58883 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
58885 this.updateColumns();
58889 onRowSelect : function(rowIndex){
58890 var row = this.getRowComposite(rowIndex);
58891 row.addClass("x-grid-row-selected");
58894 onRowDeselect : function(rowIndex){
58895 var row = this.getRowComposite(rowIndex);
58896 row.removeClass("x-grid-row-selected");
58899 onCellSelect : function(row, col){
58900 var cell = this.getCell(row, col);
58902 Roo.fly(cell).addClass("x-grid-cell-selected");
58906 onCellDeselect : function(row, col){
58907 var cell = this.getCell(row, col);
58909 Roo.fly(cell).removeClass("x-grid-cell-selected");
58913 updateHeaderSortState : function(){
58915 // sort state can be single { field: xxx, direction : yyy}
58916 // or { xxx=>ASC , yyy : DESC ..... }
58919 if (!this.ds.multiSort) {
58920 var state = this.ds.getSortState();
58924 mstate[state.field] = state.direction;
58925 // FIXME... - this is not used here.. but might be elsewhere..
58926 this.sortState = state;
58929 mstate = this.ds.sortToggle;
58931 //remove existing sort classes..
58933 var sc = this.sortClasses;
58934 var hds = this.el.select(this.headerSelector).removeClass(sc);
58936 for(var f in mstate) {
58938 var sortColumn = this.cm.findColumnIndex(f);
58940 if(sortColumn != -1){
58941 var sortDir = mstate[f];
58942 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
58951 handleHeaderClick : function(g, index,e){
58953 Roo.log("header click");
58956 // touch events on header are handled by context
58957 this.handleHdCtx(g,index,e);
58962 if(this.headersDisabled){
58965 var dm = g.dataSource, cm = g.colModel;
58966 if(!cm.isSortable(index)){
58971 if (dm.multiSort) {
58972 // update the sortOrder
58974 for(var i = 0; i < cm.config.length; i++ ) {
58976 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
58977 continue; // dont' bother, it's not in sort list or being set.
58980 so.push(cm.config[i].dataIndex);
58986 dm.sort(cm.getDataIndex(index));
58990 destroy : function(){
58992 this.colMenu.removeAll();
58993 Roo.menu.MenuMgr.unregister(this.colMenu);
58994 this.colMenu.getEl().remove();
58995 delete this.colMenu;
58998 this.hmenu.removeAll();
58999 Roo.menu.MenuMgr.unregister(this.hmenu);
59000 this.hmenu.getEl().remove();
59003 if(this.grid.enableColumnMove){
59004 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
59006 for(var dd in dds){
59007 if(!dds[dd].config.isTarget && dds[dd].dragElId){
59008 var elid = dds[dd].dragElId;
59010 Roo.get(elid).remove();
59011 } else if(dds[dd].config.isTarget){
59012 dds[dd].proxyTop.remove();
59013 dds[dd].proxyBottom.remove();
59016 if(Roo.dd.DDM.locationCache[dd]){
59017 delete Roo.dd.DDM.locationCache[dd];
59020 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
59023 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
59024 this.bind(null, null);
59025 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
59028 handleLockChange : function(){
59029 this.refresh(true);
59032 onDenyColumnLock : function(){
59036 onDenyColumnHide : function(){
59040 handleHdMenuClick : function(item){
59041 var index = this.hdCtxIndex;
59042 var cm = this.cm, ds = this.ds;
59045 ds.sort(cm.getDataIndex(index), "ASC");
59048 ds.sort(cm.getDataIndex(index), "DESC");
59051 var lc = cm.getLockedCount();
59052 if(cm.getColumnCount(true) <= lc+1){
59053 this.onDenyColumnLock();
59057 cm.setLocked(index, true, true);
59058 cm.moveColumn(index, lc);
59059 this.grid.fireEvent("columnmove", index, lc);
59061 cm.setLocked(index, true);
59065 var lc = cm.getLockedCount();
59066 if((lc-1) != index){
59067 cm.setLocked(index, false, true);
59068 cm.moveColumn(index, lc-1);
59069 this.grid.fireEvent("columnmove", index, lc-1);
59071 cm.setLocked(index, false);
59074 case 'wider': // used to expand cols on touch..
59076 var cw = cm.getColumnWidth(index);
59077 cw += (item.id == 'wider' ? 1 : -1) * 50;
59078 cw = Math.max(0, cw);
59079 cw = Math.min(cw,4000);
59080 cm.setColumnWidth(index, cw);
59084 index = cm.getIndexById(item.id.substr(4));
59086 if(item.checked && cm.getColumnCount(true) <= 1){
59087 this.onDenyColumnHide();
59090 cm.setHidden(index, item.checked);
59096 beforeColMenuShow : function(){
59097 var cm = this.cm, colCount = cm.getColumnCount();
59098 this.colMenu.removeAll();
59099 for(var i = 0; i < colCount; i++){
59100 this.colMenu.add(new Roo.menu.CheckItem({
59101 id: "col-"+cm.getColumnId(i),
59102 text: cm.getColumnHeader(i),
59103 checked: !cm.isHidden(i),
59109 handleHdCtx : function(g, index, e){
59111 var hd = this.getHeaderCell(index);
59112 this.hdCtxIndex = index;
59113 var ms = this.hmenu.items, cm = this.cm;
59114 ms.get("asc").setDisabled(!cm.isSortable(index));
59115 ms.get("desc").setDisabled(!cm.isSortable(index));
59116 if(this.grid.enableColLock !== false){
59117 ms.get("lock").setDisabled(cm.isLocked(index));
59118 ms.get("unlock").setDisabled(!cm.isLocked(index));
59120 this.hmenu.show(hd, "tl-bl");
59123 handleHdOver : function(e){
59124 var hd = this.findHeaderCell(e.getTarget());
59125 if(hd && !this.headersDisabled){
59126 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
59127 this.fly(hd).addClass("x-grid-hd-over");
59132 handleHdOut : function(e){
59133 var hd = this.findHeaderCell(e.getTarget());
59135 this.fly(hd).removeClass("x-grid-hd-over");
59139 handleSplitDblClick : function(e, t){
59140 var i = this.getCellIndex(t);
59141 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
59142 this.autoSizeColumn(i, true);
59147 render : function(){
59150 var colCount = cm.getColumnCount();
59152 if(this.grid.monitorWindowResize === true){
59153 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
59155 var header = this.renderHeaders();
59156 var body = this.templates.body.apply({rows:""});
59157 var html = this.templates.master.apply({
59160 lockedHeader: header[0],
59164 //this.updateColumns();
59166 this.grid.getGridEl().dom.innerHTML = html;
59168 this.initElements();
59170 // a kludge to fix the random scolling effect in webkit
59171 this.el.on("scroll", function() {
59172 this.el.dom.scrollTop=0; // hopefully not recursive..
59175 this.scroller.on("scroll", this.handleScroll, this);
59176 this.lockedBody.on("mousewheel", this.handleWheel, this);
59177 this.mainBody.on("mousewheel", this.handleWheel, this);
59179 this.mainHd.on("mouseover", this.handleHdOver, this);
59180 this.mainHd.on("mouseout", this.handleHdOut, this);
59181 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
59182 {delegate: "."+this.splitClass});
59184 this.lockedHd.on("mouseover", this.handleHdOver, this);
59185 this.lockedHd.on("mouseout", this.handleHdOut, this);
59186 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
59187 {delegate: "."+this.splitClass});
59189 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
59190 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
59193 this.updateSplitters();
59195 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
59196 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
59197 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
59200 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
59201 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
59203 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
59204 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
59206 if(this.grid.enableColLock !== false){
59207 this.hmenu.add('-',
59208 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
59209 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
59213 this.hmenu.add('-',
59214 {id:"wider", text: this.columnsWiderText},
59215 {id:"narrow", text: this.columnsNarrowText }
59221 if(this.grid.enableColumnHide !== false){
59223 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
59224 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
59225 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
59227 this.hmenu.add('-',
59228 {id:"columns", text: this.columnsText, menu: this.colMenu}
59231 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
59233 this.grid.on("headercontextmenu", this.handleHdCtx, this);
59236 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
59237 this.dd = new Roo.grid.GridDragZone(this.grid, {
59238 ddGroup : this.grid.ddGroup || 'GridDD'
59244 for(var i = 0; i < colCount; i++){
59245 if(cm.isHidden(i)){
59246 this.hideColumn(i);
59248 if(cm.config[i].align){
59249 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
59250 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
59254 this.updateHeaderSortState();
59256 this.beforeInitialResize();
59259 // two part rendering gives faster view to the user
59260 this.renderPhase2.defer(1, this);
59263 renderPhase2 : function(){
59264 // render the rows now
59266 if(this.grid.autoSizeColumns){
59267 this.autoSizeColumns();
59271 beforeInitialResize : function(){
59275 onColumnSplitterMoved : function(i, w){
59276 this.userResized = true;
59277 var cm = this.grid.colModel;
59278 cm.setColumnWidth(i, w, true);
59279 var cid = cm.getColumnId(i);
59280 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
59281 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
59282 this.updateSplitters();
59284 this.grid.fireEvent("columnresize", i, w);
59287 syncRowHeights : function(startIndex, endIndex){
59288 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
59289 startIndex = startIndex || 0;
59290 var mrows = this.getBodyTable().rows;
59291 var lrows = this.getLockedTable().rows;
59292 var len = mrows.length-1;
59293 endIndex = Math.min(endIndex || len, len);
59294 for(var i = startIndex; i <= endIndex; i++){
59295 var m = mrows[i], l = lrows[i];
59296 var h = Math.max(m.offsetHeight, l.offsetHeight);
59297 m.style.height = l.style.height = h + "px";
59302 layout : function(initialRender, is2ndPass)
59305 var auto = g.autoHeight;
59306 var scrollOffset = 16;
59307 var c = g.getGridEl(), cm = this.cm,
59308 expandCol = g.autoExpandColumn,
59310 //c.beginMeasure();
59312 if(!c.dom.offsetWidth){ // display:none?
59314 this.lockedWrap.show();
59315 this.mainWrap.show();
59320 var hasLock = this.cm.isLocked(0);
59322 var tbh = this.headerPanel.getHeight();
59323 var bbh = this.footerPanel.getHeight();
59326 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
59327 var newHeight = ch + c.getBorderWidth("tb");
59329 newHeight = Math.min(g.maxHeight, newHeight);
59331 c.setHeight(newHeight);
59335 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
59338 var s = this.scroller;
59340 var csize = c.getSize(true);
59342 this.el.setSize(csize.width, csize.height);
59344 this.headerPanel.setWidth(csize.width);
59345 this.footerPanel.setWidth(csize.width);
59347 var hdHeight = this.mainHd.getHeight();
59348 var vw = csize.width;
59349 var vh = csize.height - (tbh + bbh);
59353 var bt = this.getBodyTable();
59355 if(cm.getLockedCount() == cm.config.length){
59356 bt = this.getLockedTable();
59359 var ltWidth = hasLock ?
59360 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
59362 var scrollHeight = bt.offsetHeight;
59363 var scrollWidth = ltWidth + bt.offsetWidth;
59364 var vscroll = false, hscroll = false;
59366 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
59368 var lw = this.lockedWrap, mw = this.mainWrap;
59369 var lb = this.lockedBody, mb = this.mainBody;
59371 setTimeout(function(){
59372 var t = s.dom.offsetTop;
59373 var w = s.dom.clientWidth,
59374 h = s.dom.clientHeight;
59377 lw.setSize(ltWidth, h);
59379 mw.setLeftTop(ltWidth, t);
59380 mw.setSize(w-ltWidth, h);
59382 lb.setHeight(h-hdHeight);
59383 mb.setHeight(h-hdHeight);
59385 if(is2ndPass !== true && !gv.userResized && expandCol){
59386 // high speed resize without full column calculation
59388 var ci = cm.getIndexById(expandCol);
59390 ci = cm.findColumnIndex(expandCol);
59392 ci = Math.max(0, ci); // make sure it's got at least the first col.
59393 var expandId = cm.getColumnId(ci);
59394 var tw = cm.getTotalWidth(false);
59395 var currentWidth = cm.getColumnWidth(ci);
59396 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
59397 if(currentWidth != cw){
59398 cm.setColumnWidth(ci, cw, true);
59399 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
59400 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
59401 gv.updateSplitters();
59402 gv.layout(false, true);
59414 onWindowResize : function(){
59415 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
59421 appendFooter : function(parentEl){
59425 sortAscText : "Sort Ascending",
59426 sortDescText : "Sort Descending",
59427 lockText : "Lock Column",
59428 unlockText : "Unlock Column",
59429 columnsText : "Columns",
59431 columnsWiderText : "Wider",
59432 columnsNarrowText : "Thinner"
59436 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
59437 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
59438 this.proxy.el.addClass('x-grid3-col-dd');
59441 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
59442 handleMouseDown : function(e){
59446 callHandleMouseDown : function(e){
59447 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
59452 * Ext JS Library 1.1.1
59453 * Copyright(c) 2006-2007, Ext JS, LLC.
59455 * Originally Released Under LGPL - original licence link has changed is not relivant.
59458 * <script type="text/javascript">
59461 * @extends Roo.dd.DDProxy
59462 * @class Roo.grid.SplitDragZone
59463 * Support for Column Header resizing
59465 * @param {Object} config
59468 // This is a support class used internally by the Grid components
59469 Roo.grid.SplitDragZone = function(grid, hd, hd2){
59471 this.view = grid.getView();
59472 this.proxy = this.view.resizeProxy;
59473 Roo.grid.SplitDragZone.superclass.constructor.call(
59476 "gridSplitters" + this.grid.getGridEl().id, // SGROUP
59478 dragElId : Roo.id(this.proxy.dom),
59483 this.setHandleElId(Roo.id(hd));
59484 if (hd2 !== false) {
59485 this.setOuterHandleElId(Roo.id(hd2));
59488 this.scroll = false;
59490 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
59491 fly: Roo.Element.fly,
59493 b4StartDrag : function(x, y){
59494 this.view.headersDisabled = true;
59495 var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
59496 this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
59498 this.proxy.setHeight(h);
59500 // for old system colWidth really stored the actual width?
59501 // in bootstrap we tried using xs/ms/etc.. to do % sizing?
59502 // which in reality did not work.. - it worked only for fixed sizes
59503 // for resizable we need to use actual sizes.
59504 var w = this.cm.getColumnWidth(this.cellIndex);
59505 if (!this.view.mainWrap) {
59507 w = this.view.getHeaderIndex(this.cellIndex).getWidth();
59512 // this was w-this.grid.minColumnWidth;
59513 // doesnt really make sense? - w = thie curren width or the rendered one?
59514 var minw = Math.max(w-this.grid.minColumnWidth, 0);
59515 this.resetConstraints();
59516 this.setXConstraint(minw, 1000);
59517 this.setYConstraint(0, 0);
59518 this.minX = x - minw;
59519 this.maxX = x + 1000;
59521 if (!this.view.mainWrap) { // this is Bootstrap code..
59522 this.getDragEl().style.display='block';
59525 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
59529 handleMouseDown : function(e){
59530 ev = Roo.EventObject.setEvent(e);
59531 var t = this.fly(ev.getTarget());
59532 if(t.hasClass("x-grid-split")){
59533 this.cellIndex = this.view.getCellIndex(t.dom);
59534 this.split = t.dom;
59535 this.cm = this.grid.colModel;
59536 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
59537 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
59542 endDrag : function(e){
59543 this.view.headersDisabled = false;
59544 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
59545 var diff = endX - this.startPos;
59547 var w = this.cm.getColumnWidth(this.cellIndex);
59548 if (!this.view.mainWrap) {
59551 this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
59554 autoOffset : function(){
59555 this.setDelta(0,0);
59559 * Ext JS Library 1.1.1
59560 * Copyright(c) 2006-2007, Ext JS, LLC.
59562 * Originally Released Under LGPL - original licence link has changed is not relivant.
59565 * <script type="text/javascript">
59569 // This is a support class used internally by the Grid components
59570 Roo.grid.GridDragZone = function(grid, config){
59571 this.view = grid.getView();
59572 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
59573 if(this.view.lockedBody){
59574 this.setHandleElId(Roo.id(this.view.mainBody.dom));
59575 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
59577 this.scroll = false;
59579 this.ddel = document.createElement('div');
59580 this.ddel.className = 'x-grid-dd-wrap';
59583 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
59584 ddGroup : "GridDD",
59586 getDragData : function(e){
59587 var t = Roo.lib.Event.getTarget(e);
59588 var rowIndex = this.view.findRowIndex(t);
59589 var sm = this.grid.selModel;
59591 //Roo.log(rowIndex);
59593 if (sm.getSelectedCell) {
59594 // cell selection..
59595 if (!sm.getSelectedCell()) {
59598 if (rowIndex != sm.getSelectedCell()[0]) {
59603 if (sm.getSelections && sm.getSelections().length < 1) {
59608 // before it used to all dragging of unseleted... - now we dont do that.
59609 if(rowIndex !== false){
59614 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
59616 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
59619 if (e.hasModifier()){
59620 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
59623 Roo.log("getDragData");
59628 rowIndex: rowIndex,
59629 selections: sm.getSelections ? sm.getSelections() : (
59630 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
59637 onInitDrag : function(e){
59638 var data = this.dragData;
59639 this.ddel.innerHTML = this.grid.getDragDropText();
59640 this.proxy.update(this.ddel);
59641 // fire start drag?
59644 afterRepair : function(){
59645 this.dragging = false;
59648 getRepairXY : function(e, data){
59652 onEndDrag : function(data, e){
59656 onValidDrop : function(dd, e, id){
59661 beforeInvalidDrop : function(e, id){
59666 * Ext JS Library 1.1.1
59667 * Copyright(c) 2006-2007, Ext JS, LLC.
59669 * Originally Released Under LGPL - original licence link has changed is not relivant.
59672 * <script type="text/javascript">
59677 * @class Roo.grid.ColumnModel
59678 * @extends Roo.util.Observable
59679 * This is the default implementation of a ColumnModel used by the Grid. It defines
59680 * the columns in the grid.
59683 var colModel = new Roo.grid.ColumnModel([
59684 {header: "Ticker", width: 60, sortable: true, locked: true},
59685 {header: "Company Name", width: 150, sortable: true},
59686 {header: "Market Cap.", width: 100, sortable: true},
59687 {header: "$ Sales", width: 100, sortable: true, renderer: money},
59688 {header: "Employees", width: 100, sortable: true, resizable: false}
59693 * The config options listed for this class are options which may appear in each
59694 * individual column definition.
59695 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
59697 * @param {Object} config An Array of column config objects. See this class's
59698 * config objects for details.
59700 Roo.grid.ColumnModel = function(config){
59702 * The config passed into the constructor
59704 this.config = []; //config;
59707 // if no id, create one
59708 // if the column does not have a dataIndex mapping,
59709 // map it to the order it is in the config
59710 for(var i = 0, len = config.length; i < len; i++){
59711 this.addColumn(config[i]);
59716 * The width of columns which have no width specified (defaults to 100)
59719 this.defaultWidth = 100;
59722 * Default sortable of columns which have no sortable specified (defaults to false)
59725 this.defaultSortable = false;
59729 * @event widthchange
59730 * Fires when the width of a column changes.
59731 * @param {ColumnModel} this
59732 * @param {Number} columnIndex The column index
59733 * @param {Number} newWidth The new width
59735 "widthchange": true,
59737 * @event headerchange
59738 * Fires when the text of a header changes.
59739 * @param {ColumnModel} this
59740 * @param {Number} columnIndex The column index
59741 * @param {Number} newText The new header text
59743 "headerchange": true,
59745 * @event hiddenchange
59746 * Fires when a column is hidden or "unhidden".
59747 * @param {ColumnModel} this
59748 * @param {Number} columnIndex The column index
59749 * @param {Boolean} hidden true if hidden, false otherwise
59751 "hiddenchange": true,
59753 * @event columnmoved
59754 * Fires when a column is moved.
59755 * @param {ColumnModel} this
59756 * @param {Number} oldIndex
59757 * @param {Number} newIndex
59759 "columnmoved" : true,
59761 * @event columlockchange
59762 * Fires when a column's locked state is changed
59763 * @param {ColumnModel} this
59764 * @param {Number} colIndex
59765 * @param {Boolean} locked true if locked
59767 "columnlockchange" : true
59769 Roo.grid.ColumnModel.superclass.constructor.call(this);
59771 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
59773 * @cfg {String} header The header text to display in the Grid view.
59776 * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
59779 * @cfg {String} smHeader Header at Bootsrap Small width
59782 * @cfg {String} mdHeader Header at Bootsrap Medium width
59785 * @cfg {String} lgHeader Header at Bootsrap Large width
59788 * @cfg {String} xlHeader Header at Bootsrap extra Large width
59791 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
59792 * {@link Roo.data.Record} definition from which to draw the column's value. If not
59793 * specified, the column's index is used as an index into the Record's data Array.
59796 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
59797 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
59800 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
59801 * Defaults to the value of the {@link #defaultSortable} property.
59802 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
59805 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
59808 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
59811 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
59814 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
59817 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
59818 * given the cell's data value. See {@link #setRenderer}. If not specified, the
59819 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
59820 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
59823 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
59826 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
59829 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
59832 * @cfg {String} cursor (Optional)
59835 * @cfg {String} tooltip (Optional)
59838 * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
59841 * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
59844 * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
59847 * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
59850 * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
59853 * Returns the id of the column at the specified index.
59854 * @param {Number} index The column index
59855 * @return {String} the id
59857 getColumnId : function(index){
59858 return this.config[index].id;
59862 * Returns the column for a specified id.
59863 * @param {String} id The column id
59864 * @return {Object} the column
59866 getColumnById : function(id){
59867 return this.lookup[id];
59872 * Returns the column Object for a specified dataIndex.
59873 * @param {String} dataIndex The column dataIndex
59874 * @return {Object|Boolean} the column or false if not found
59876 getColumnByDataIndex: function(dataIndex){
59877 var index = this.findColumnIndex(dataIndex);
59878 return index > -1 ? this.config[index] : false;
59882 * Returns the index for a specified column id.
59883 * @param {String} id The column id
59884 * @return {Number} the index, or -1 if not found
59886 getIndexById : function(id){
59887 for(var i = 0, len = this.config.length; i < len; i++){
59888 if(this.config[i].id == id){
59896 * Returns the index for a specified column dataIndex.
59897 * @param {String} dataIndex The column dataIndex
59898 * @return {Number} the index, or -1 if not found
59901 findColumnIndex : function(dataIndex){
59902 for(var i = 0, len = this.config.length; i < len; i++){
59903 if(this.config[i].dataIndex == dataIndex){
59911 moveColumn : function(oldIndex, newIndex){
59912 var c = this.config[oldIndex];
59913 this.config.splice(oldIndex, 1);
59914 this.config.splice(newIndex, 0, c);
59915 this.dataMap = null;
59916 this.fireEvent("columnmoved", this, oldIndex, newIndex);
59919 isLocked : function(colIndex){
59920 return this.config[colIndex].locked === true;
59923 setLocked : function(colIndex, value, suppressEvent){
59924 if(this.isLocked(colIndex) == value){
59927 this.config[colIndex].locked = value;
59928 if(!suppressEvent){
59929 this.fireEvent("columnlockchange", this, colIndex, value);
59933 getTotalLockedWidth : function(){
59934 var totalWidth = 0;
59935 for(var i = 0; i < this.config.length; i++){
59936 if(this.isLocked(i) && !this.isHidden(i)){
59937 this.totalWidth += this.getColumnWidth(i);
59943 getLockedCount : function(){
59944 for(var i = 0, len = this.config.length; i < len; i++){
59945 if(!this.isLocked(i)){
59950 return this.config.length;
59954 * Returns the number of columns.
59957 getColumnCount : function(visibleOnly){
59958 if(visibleOnly === true){
59960 for(var i = 0, len = this.config.length; i < len; i++){
59961 if(!this.isHidden(i)){
59967 return this.config.length;
59971 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
59972 * @param {Function} fn
59973 * @param {Object} scope (optional)
59974 * @return {Array} result
59976 getColumnsBy : function(fn, scope){
59978 for(var i = 0, len = this.config.length; i < len; i++){
59979 var c = this.config[i];
59980 if(fn.call(scope||this, c, i) === true){
59988 * Returns true if the specified column is sortable.
59989 * @param {Number} col The column index
59990 * @return {Boolean}
59992 isSortable : function(col){
59993 if(typeof this.config[col].sortable == "undefined"){
59994 return this.defaultSortable;
59996 return this.config[col].sortable;
60000 * Returns the rendering (formatting) function defined for the column.
60001 * @param {Number} col The column index.
60002 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
60004 getRenderer : function(col){
60005 if(!this.config[col].renderer){
60006 return Roo.grid.ColumnModel.defaultRenderer;
60008 return this.config[col].renderer;
60012 * Sets the rendering (formatting) function for a column.
60013 * @param {Number} col The column index
60014 * @param {Function} fn The function to use to process the cell's raw data
60015 * to return HTML markup for the grid view. The render function is called with
60016 * the following parameters:<ul>
60017 * <li>Data value.</li>
60018 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
60019 * <li>css A CSS style string to apply to the table cell.</li>
60020 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
60021 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
60022 * <li>Row index</li>
60023 * <li>Column index</li>
60024 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
60026 setRenderer : function(col, fn){
60027 this.config[col].renderer = fn;
60031 * Returns the width for the specified column.
60032 * @param {Number} col The column index
60033 * @param (optional) {String} gridSize bootstrap width size.
60036 getColumnWidth : function(col, gridSize)
60038 var cfg = this.config[col];
60040 if (typeof(gridSize) == 'undefined') {
60041 return cfg.width * 1 || this.defaultWidth;
60043 if (gridSize === false) { // if we set it..
60044 return cfg.width || false;
60046 var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
60048 for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
60049 if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
60052 return cfg[ sizes[i] ];
60059 * Sets the width for a column.
60060 * @param {Number} col The column index
60061 * @param {Number} width The new width
60063 setColumnWidth : function(col, width, suppressEvent){
60064 this.config[col].width = width;
60065 this.totalWidth = null;
60066 if(!suppressEvent){
60067 this.fireEvent("widthchange", this, col, width);
60072 * Returns the total width of all columns.
60073 * @param {Boolean} includeHidden True to include hidden column widths
60076 getTotalWidth : function(includeHidden){
60077 if(!this.totalWidth){
60078 this.totalWidth = 0;
60079 for(var i = 0, len = this.config.length; i < len; i++){
60080 if(includeHidden || !this.isHidden(i)){
60081 this.totalWidth += this.getColumnWidth(i);
60085 return this.totalWidth;
60089 * Returns the header for the specified column.
60090 * @param {Number} col The column index
60093 getColumnHeader : function(col){
60094 return this.config[col].header;
60098 * Sets the header for a column.
60099 * @param {Number} col The column index
60100 * @param {String} header The new header
60102 setColumnHeader : function(col, header){
60103 this.config[col].header = header;
60104 this.fireEvent("headerchange", this, col, header);
60108 * Returns the tooltip for the specified column.
60109 * @param {Number} col The column index
60112 getColumnTooltip : function(col){
60113 return this.config[col].tooltip;
60116 * Sets the tooltip for a column.
60117 * @param {Number} col The column index
60118 * @param {String} tooltip The new tooltip
60120 setColumnTooltip : function(col, tooltip){
60121 this.config[col].tooltip = tooltip;
60125 * Returns the dataIndex for the specified column.
60126 * @param {Number} col The column index
60129 getDataIndex : function(col){
60130 return this.config[col].dataIndex;
60134 * Sets the dataIndex for a column.
60135 * @param {Number} col The column index
60136 * @param {Number} dataIndex The new dataIndex
60138 setDataIndex : function(col, dataIndex){
60139 this.config[col].dataIndex = dataIndex;
60145 * Returns true if the cell is editable.
60146 * @param {Number} colIndex The column index
60147 * @param {Number} rowIndex The row index - this is nto actually used..?
60148 * @return {Boolean}
60150 isCellEditable : function(colIndex, rowIndex){
60151 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
60155 * Returns the editor defined for the cell/column.
60156 * return false or null to disable editing.
60157 * @param {Number} colIndex The column index
60158 * @param {Number} rowIndex The row index
60161 getCellEditor : function(colIndex, rowIndex){
60162 return this.config[colIndex].editor;
60166 * Sets if a column is editable.
60167 * @param {Number} col The column index
60168 * @param {Boolean} editable True if the column is editable
60170 setEditable : function(col, editable){
60171 this.config[col].editable = editable;
60176 * Returns true if the column is hidden.
60177 * @param {Number} colIndex The column index
60178 * @return {Boolean}
60180 isHidden : function(colIndex){
60181 return this.config[colIndex].hidden;
60186 * Returns true if the column width cannot be changed
60188 isFixed : function(colIndex){
60189 return this.config[colIndex].fixed;
60193 * Returns true if the column can be resized
60194 * @return {Boolean}
60196 isResizable : function(colIndex){
60197 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
60200 * Sets if a column is hidden.
60201 * @param {Number} colIndex The column index
60202 * @param {Boolean} hidden True if the column is hidden
60204 setHidden : function(colIndex, hidden){
60205 this.config[colIndex].hidden = hidden;
60206 this.totalWidth = null;
60207 this.fireEvent("hiddenchange", this, colIndex, hidden);
60211 * Sets the editor for a column.
60212 * @param {Number} col The column index
60213 * @param {Object} editor The editor object
60215 setEditor : function(col, editor){
60216 this.config[col].editor = editor;
60219 * Add a column (experimental...) - defaults to adding to the end..
60220 * @param {Object} config
60222 addColumn : function(c)
60225 var i = this.config.length;
60226 this.config[i] = c;
60228 if(typeof c.dataIndex == "undefined"){
60231 if(typeof c.renderer == "string"){
60232 c.renderer = Roo.util.Format[c.renderer];
60234 if(typeof c.id == "undefined"){
60237 if(c.editor && c.editor.xtype){
60238 c.editor = Roo.factory(c.editor, Roo.grid);
60240 if(c.editor && c.editor.isFormField){
60241 c.editor = new Roo.grid.GridEditor(c.editor);
60243 this.lookup[c.id] = c;
60248 Roo.grid.ColumnModel.defaultRenderer = function(value)
60250 if(typeof value == "object") {
60253 if(typeof value == "string" && value.length < 1){
60257 return String.format("{0}", value);
60260 // Alias for backwards compatibility
60261 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
60264 * Ext JS Library 1.1.1
60265 * Copyright(c) 2006-2007, Ext JS, LLC.
60267 * Originally Released Under LGPL - original licence link has changed is not relivant.
60270 * <script type="text/javascript">
60274 * @class Roo.grid.AbstractSelectionModel
60275 * @extends Roo.util.Observable
60277 * Abstract base class for grid SelectionModels. It provides the interface that should be
60278 * implemented by descendant classes. This class should not be directly instantiated.
60281 Roo.grid.AbstractSelectionModel = function(){
60282 this.locked = false;
60283 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
60286 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
60287 /** @ignore Called by the grid automatically. Do not call directly. */
60288 init : function(grid){
60294 * Locks the selections.
60297 this.locked = true;
60301 * Unlocks the selections.
60303 unlock : function(){
60304 this.locked = false;
60308 * Returns true if the selections are locked.
60309 * @return {Boolean}
60311 isLocked : function(){
60312 return this.locked;
60316 * Ext JS Library 1.1.1
60317 * Copyright(c) 2006-2007, Ext JS, LLC.
60319 * Originally Released Under LGPL - original licence link has changed is not relivant.
60322 * <script type="text/javascript">
60325 * @extends Roo.grid.AbstractSelectionModel
60326 * @class Roo.grid.RowSelectionModel
60327 * The default SelectionModel used by {@link Roo.grid.Grid}.
60328 * It supports multiple selections and keyboard selection/navigation.
60330 * @param {Object} config
60332 Roo.grid.RowSelectionModel = function(config){
60333 Roo.apply(this, config);
60334 this.selections = new Roo.util.MixedCollection(false, function(o){
60339 this.lastActive = false;
60343 * @event selectionchange
60344 * Fires when the selection changes
60345 * @param {SelectionModel} this
60347 "selectionchange" : true,
60349 * @event afterselectionchange
60350 * Fires after the selection changes (eg. by key press or clicking)
60351 * @param {SelectionModel} this
60353 "afterselectionchange" : true,
60355 * @event beforerowselect
60356 * Fires when a row is selected being selected, return false to cancel.
60357 * @param {SelectionModel} this
60358 * @param {Number} rowIndex The selected index
60359 * @param {Boolean} keepExisting False if other selections will be cleared
60361 "beforerowselect" : true,
60364 * Fires when a row is selected.
60365 * @param {SelectionModel} this
60366 * @param {Number} rowIndex The selected index
60367 * @param {Roo.data.Record} r The record
60369 "rowselect" : true,
60371 * @event rowdeselect
60372 * Fires when a row is deselected.
60373 * @param {SelectionModel} this
60374 * @param {Number} rowIndex The selected index
60376 "rowdeselect" : true
60378 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
60379 this.locked = false;
60382 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
60384 * @cfg {Boolean} singleSelect
60385 * True to allow selection of only one row at a time (defaults to false)
60387 singleSelect : false,
60390 initEvents : function(){
60392 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
60393 this.grid.on("mousedown", this.handleMouseDown, this);
60394 }else{ // allow click to work like normal
60395 this.grid.on("rowclick", this.handleDragableRowClick, this);
60397 // bootstrap does not have a view..
60398 var view = this.grid.view ? this.grid.view : this.grid;
60399 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
60400 "up" : function(e){
60402 this.selectPrevious(e.shiftKey);
60403 }else if(this.last !== false && this.lastActive !== false){
60404 var last = this.last;
60405 this.selectRange(this.last, this.lastActive-1);
60406 view.focusRow(this.lastActive);
60407 if(last !== false){
60411 this.selectFirstRow();
60413 this.fireEvent("afterselectionchange", this);
60415 "down" : function(e){
60417 this.selectNext(e.shiftKey);
60418 }else if(this.last !== false && this.lastActive !== false){
60419 var last = this.last;
60420 this.selectRange(this.last, this.lastActive+1);
60421 view.focusRow(this.lastActive);
60422 if(last !== false){
60426 this.selectFirstRow();
60428 this.fireEvent("afterselectionchange", this);
60434 view.on("refresh", this.onRefresh, this);
60435 view.on("rowupdated", this.onRowUpdated, this);
60436 view.on("rowremoved", this.onRemove, this);
60440 onRefresh : function(){
60441 var ds = this.grid.ds, i, v = this.grid.view;
60442 var s = this.selections;
60443 s.each(function(r){
60444 if((i = ds.indexOfId(r.id)) != -1){
60446 s.add(ds.getAt(i)); // updating the selection relate data
60454 onRemove : function(v, index, r){
60455 this.selections.remove(r);
60459 onRowUpdated : function(v, index, r){
60460 if(this.isSelected(r)){
60461 v.onRowSelect(index);
60467 * @param {Array} records The records to select
60468 * @param {Boolean} keepExisting (optional) True to keep existing selections
60470 selectRecords : function(records, keepExisting){
60472 this.clearSelections();
60474 var ds = this.grid.ds;
60475 for(var i = 0, len = records.length; i < len; i++){
60476 this.selectRow(ds.indexOf(records[i]), true);
60481 * Gets the number of selected rows.
60484 getCount : function(){
60485 return this.selections.length;
60489 * Selects the first row in the grid.
60491 selectFirstRow : function(){
60496 * Select the last row.
60497 * @param {Boolean} keepExisting (optional) True to keep existing selections
60499 selectLastRow : function(keepExisting){
60500 this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
60504 * Selects the row immediately following the last selected row.
60505 * @param {Boolean} keepExisting (optional) True to keep existing selections
60507 selectNext : function(keepExisting){
60508 if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
60509 this.selectRow(this.last+1, keepExisting);
60510 var view = this.grid.view ? this.grid.view : this.grid;
60511 view.focusRow(this.last);
60516 * Selects the row that precedes the last selected row.
60517 * @param {Boolean} keepExisting (optional) True to keep existing selections
60519 selectPrevious : function(keepExisting){
60521 this.selectRow(this.last-1, keepExisting);
60522 var view = this.grid.view ? this.grid.view : this.grid;
60523 view.focusRow(this.last);
60528 * Returns the selected records
60529 * @return {Array} Array of selected records
60531 getSelections : function(){
60532 return [].concat(this.selections.items);
60536 * Returns the first selected record.
60539 getSelected : function(){
60540 return this.selections.itemAt(0);
60545 * Clears all selections.
60547 clearSelections : function(fast){
60552 var ds = this.grid.ds;
60553 var s = this.selections;
60554 s.each(function(r){
60555 this.deselectRow(ds.indexOfId(r.id));
60559 this.selections.clear();
60566 * Selects all rows.
60568 selectAll : function(){
60572 this.selections.clear();
60573 for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
60574 this.selectRow(i, true);
60579 * Returns True if there is a selection.
60580 * @return {Boolean}
60582 hasSelection : function(){
60583 return this.selections.length > 0;
60587 * Returns True if the specified row is selected.
60588 * @param {Number/Record} record The record or index of the record to check
60589 * @return {Boolean}
60591 isSelected : function(index){
60592 var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
60593 return (r && this.selections.key(r.id) ? true : false);
60597 * Returns True if the specified record id is selected.
60598 * @param {String} id The id of record to check
60599 * @return {Boolean}
60601 isIdSelected : function(id){
60602 return (this.selections.key(id) ? true : false);
60606 handleMouseDown : function(e, t)
60608 var view = this.grid.view ? this.grid.view : this.grid;
60610 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
60613 if(e.shiftKey && this.last !== false){
60614 var last = this.last;
60615 this.selectRange(last, rowIndex, e.ctrlKey);
60616 this.last = last; // reset the last
60617 view.focusRow(rowIndex);
60619 var isSelected = this.isSelected(rowIndex);
60620 if(e.button !== 0 && isSelected){
60621 view.focusRow(rowIndex);
60622 }else if(e.ctrlKey && isSelected){
60623 this.deselectRow(rowIndex);
60624 }else if(!isSelected){
60625 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
60626 view.focusRow(rowIndex);
60629 this.fireEvent("afterselectionchange", this);
60632 handleDragableRowClick : function(grid, rowIndex, e)
60634 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
60635 this.selectRow(rowIndex, false);
60636 var view = this.grid.view ? this.grid.view : this.grid;
60637 view.focusRow(rowIndex);
60638 this.fireEvent("afterselectionchange", this);
60643 * Selects multiple rows.
60644 * @param {Array} rows Array of the indexes of the row to select
60645 * @param {Boolean} keepExisting (optional) True to keep existing selections
60647 selectRows : function(rows, keepExisting){
60649 this.clearSelections();
60651 for(var i = 0, len = rows.length; i < len; i++){
60652 this.selectRow(rows[i], true);
60657 * Selects a range of rows. All rows in between startRow and endRow are also selected.
60658 * @param {Number} startRow The index of the first row in the range
60659 * @param {Number} endRow The index of the last row in the range
60660 * @param {Boolean} keepExisting (optional) True to retain existing selections
60662 selectRange : function(startRow, endRow, keepExisting){
60667 this.clearSelections();
60669 if(startRow <= endRow){
60670 for(var i = startRow; i <= endRow; i++){
60671 this.selectRow(i, true);
60674 for(var i = startRow; i >= endRow; i--){
60675 this.selectRow(i, true);
60681 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
60682 * @param {Number} startRow The index of the first row in the range
60683 * @param {Number} endRow The index of the last row in the range
60685 deselectRange : function(startRow, endRow, preventViewNotify){
60689 for(var i = startRow; i <= endRow; i++){
60690 this.deselectRow(i, preventViewNotify);
60696 * @param {Number} row The index of the row to select
60697 * @param {Boolean} keepExisting (optional) True to keep existing selections
60699 selectRow : function(index, keepExisting, preventViewNotify){
60700 if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
60703 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
60704 if(!keepExisting || this.singleSelect){
60705 this.clearSelections();
60707 var r = this.grid.ds.getAt(index);
60708 this.selections.add(r);
60709 this.last = this.lastActive = index;
60710 if(!preventViewNotify){
60711 var view = this.grid.view ? this.grid.view : this.grid;
60712 view.onRowSelect(index);
60714 this.fireEvent("rowselect", this, index, r);
60715 this.fireEvent("selectionchange", this);
60721 * @param {Number} row The index of the row to deselect
60723 deselectRow : function(index, preventViewNotify){
60727 if(this.last == index){
60730 if(this.lastActive == index){
60731 this.lastActive = false;
60733 var r = this.grid.ds.getAt(index);
60734 this.selections.remove(r);
60735 if(!preventViewNotify){
60736 var view = this.grid.view ? this.grid.view : this.grid;
60737 view.onRowDeselect(index);
60739 this.fireEvent("rowdeselect", this, index);
60740 this.fireEvent("selectionchange", this);
60744 restoreLast : function(){
60746 this.last = this._last;
60751 acceptsNav : function(row, col, cm){
60752 return !cm.isHidden(col) && cm.isCellEditable(col, row);
60756 onEditorKey : function(field, e){
60757 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
60762 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
60764 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
60766 }else if(k == e.ENTER && !e.ctrlKey){
60770 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
60772 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
60774 }else if(k == e.ESC){
60778 g.startEditing(newCell[0], newCell[1]);
60783 * Ext JS Library 1.1.1
60784 * Copyright(c) 2006-2007, Ext JS, LLC.
60786 * Originally Released Under LGPL - original licence link has changed is not relivant.
60789 * <script type="text/javascript">
60792 * @class Roo.grid.CellSelectionModel
60793 * @extends Roo.grid.AbstractSelectionModel
60794 * This class provides the basic implementation for cell selection in a grid.
60796 * @param {Object} config The object containing the configuration of this model.
60797 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
60799 Roo.grid.CellSelectionModel = function(config){
60800 Roo.apply(this, config);
60802 this.selection = null;
60806 * @event beforerowselect
60807 * Fires before a cell is selected.
60808 * @param {SelectionModel} this
60809 * @param {Number} rowIndex The selected row index
60810 * @param {Number} colIndex The selected cell index
60812 "beforecellselect" : true,
60814 * @event cellselect
60815 * Fires when a cell is selected.
60816 * @param {SelectionModel} this
60817 * @param {Number} rowIndex The selected row index
60818 * @param {Number} colIndex The selected cell index
60820 "cellselect" : true,
60822 * @event selectionchange
60823 * Fires when the active selection changes.
60824 * @param {SelectionModel} this
60825 * @param {Object} selection null for no selection or an object (o) with two properties
60827 <li>o.record: the record object for the row the selection is in</li>
60828 <li>o.cell: An array of [rowIndex, columnIndex]</li>
60831 "selectionchange" : true,
60834 * Fires when the tab (or enter) was pressed on the last editable cell
60835 * You can use this to trigger add new row.
60836 * @param {SelectionModel} this
60840 * @event beforeeditnext
60841 * Fires before the next editable sell is made active
60842 * You can use this to skip to another cell or fire the tabend
60843 * if you set cell to false
60844 * @param {Object} eventdata object : { cell : [ row, col ] }
60846 "beforeeditnext" : true
60848 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
60851 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
60853 enter_is_tab: false,
60856 initEvents : function(){
60857 this.grid.on("mousedown", this.handleMouseDown, this);
60858 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
60859 var view = this.grid.view;
60860 view.on("refresh", this.onViewChange, this);
60861 view.on("rowupdated", this.onRowUpdated, this);
60862 view.on("beforerowremoved", this.clearSelections, this);
60863 view.on("beforerowsinserted", this.clearSelections, this);
60864 if(this.grid.isEditor){
60865 this.grid.on("beforeedit", this.beforeEdit, this);
60870 beforeEdit : function(e){
60871 this.select(e.row, e.column, false, true, e.record);
60875 onRowUpdated : function(v, index, r){
60876 if(this.selection && this.selection.record == r){
60877 v.onCellSelect(index, this.selection.cell[1]);
60882 onViewChange : function(){
60883 this.clearSelections(true);
60887 * Returns the currently selected cell,.
60888 * @return {Array} The selected cell (row, column) or null if none selected.
60890 getSelectedCell : function(){
60891 return this.selection ? this.selection.cell : null;
60895 * Clears all selections.
60896 * @param {Boolean} true to prevent the gridview from being notified about the change.
60898 clearSelections : function(preventNotify){
60899 var s = this.selection;
60901 if(preventNotify !== true){
60902 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
60904 this.selection = null;
60905 this.fireEvent("selectionchange", this, null);
60910 * Returns true if there is a selection.
60911 * @return {Boolean}
60913 hasSelection : function(){
60914 return this.selection ? true : false;
60918 handleMouseDown : function(e, t){
60919 var v = this.grid.getView();
60920 if(this.isLocked()){
60923 var row = v.findRowIndex(t);
60924 var cell = v.findCellIndex(t);
60925 if(row !== false && cell !== false){
60926 this.select(row, cell);
60932 * @param {Number} rowIndex
60933 * @param {Number} collIndex
60935 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
60936 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
60937 this.clearSelections();
60938 r = r || this.grid.dataSource.getAt(rowIndex);
60941 cell : [rowIndex, colIndex]
60943 if(!preventViewNotify){
60944 var v = this.grid.getView();
60945 v.onCellSelect(rowIndex, colIndex);
60946 if(preventFocus !== true){
60947 v.focusCell(rowIndex, colIndex);
60950 this.fireEvent("cellselect", this, rowIndex, colIndex);
60951 this.fireEvent("selectionchange", this, this.selection);
60956 isSelectable : function(rowIndex, colIndex, cm){
60957 return !cm.isHidden(colIndex);
60961 handleKeyDown : function(e){
60962 //Roo.log('Cell Sel Model handleKeyDown');
60963 if(!e.isNavKeyPress()){
60966 var g = this.grid, s = this.selection;
60969 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
60971 this.select(cell[0], cell[1]);
60976 var walk = function(row, col, step){
60977 return g.walkCells(row, col, step, sm.isSelectable, sm);
60979 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
60986 // handled by onEditorKey
60987 if (g.isEditor && g.editing) {
60991 newCell = walk(r, c-1, -1);
60993 newCell = walk(r, c+1, 1);
60998 newCell = walk(r+1, c, 1);
61002 newCell = walk(r-1, c, -1);
61006 newCell = walk(r, c+1, 1);
61010 newCell = walk(r, c-1, -1);
61015 if(g.isEditor && !g.editing){
61016 g.startEditing(r, c);
61025 this.select(newCell[0], newCell[1]);
61031 acceptsNav : function(row, col, cm){
61032 return !cm.isHidden(col) && cm.isCellEditable(col, row);
61036 * @param {Number} field (not used) - as it's normally used as a listener
61037 * @param {Number} e - event - fake it by using
61039 * var e = Roo.EventObjectImpl.prototype;
61040 * e.keyCode = e.TAB
61044 onEditorKey : function(field, e){
61046 var k = e.getKey(),
61049 ed = g.activeEditor,
61051 ///Roo.log('onEditorKey' + k);
61054 if (this.enter_is_tab && k == e.ENTER) {
61060 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
61062 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
61068 } else if(k == e.ENTER && !e.ctrlKey){
61071 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
61073 } else if(k == e.ESC){
61078 var ecall = { cell : newCell, forward : forward };
61079 this.fireEvent('beforeeditnext', ecall );
61080 newCell = ecall.cell;
61081 forward = ecall.forward;
61085 //Roo.log('next cell after edit');
61086 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
61087 } else if (forward) {
61088 // tabbed past last
61089 this.fireEvent.defer(100, this, ['tabend',this]);
61094 * Ext JS Library 1.1.1
61095 * Copyright(c) 2006-2007, Ext JS, LLC.
61097 * Originally Released Under LGPL - original licence link has changed is not relivant.
61100 * <script type="text/javascript">
61104 * @class Roo.grid.EditorGrid
61105 * @extends Roo.grid.Grid
61106 * Class for creating and editable grid.
61107 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
61108 * The container MUST have some type of size defined for the grid to fill. The container will be
61109 * automatically set to position relative if it isn't already.
61110 * @param {Object} dataSource The data model to bind to
61111 * @param {Object} colModel The column model with info about this grid's columns
61113 Roo.grid.EditorGrid = function(container, config){
61114 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
61115 this.getGridEl().addClass("xedit-grid");
61117 if(!this.selModel){
61118 this.selModel = new Roo.grid.CellSelectionModel();
61121 this.activeEditor = null;
61125 * @event beforeedit
61126 * Fires before cell editing is triggered. The edit event object has the following properties <br />
61127 * <ul style="padding:5px;padding-left:16px;">
61128 * <li>grid - This grid</li>
61129 * <li>record - The record being edited</li>
61130 * <li>field - The field name being edited</li>
61131 * <li>value - The value for the field being edited.</li>
61132 * <li>row - The grid row index</li>
61133 * <li>column - The grid column index</li>
61134 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
61136 * @param {Object} e An edit event (see above for description)
61138 "beforeedit" : true,
61141 * Fires after a cell is edited. <br />
61142 * <ul style="padding:5px;padding-left:16px;">
61143 * <li>grid - This grid</li>
61144 * <li>record - The record being edited</li>
61145 * <li>field - The field name being edited</li>
61146 * <li>value - The value being set</li>
61147 * <li>originalValue - The original value for the field, before the edit.</li>
61148 * <li>row - The grid row index</li>
61149 * <li>column - The grid column index</li>
61151 * @param {Object} e An edit event (see above for description)
61153 "afteredit" : true,
61155 * @event validateedit
61156 * Fires after a cell is edited, but before the value is set in the record.
61157 * You can use this to modify the value being set in the field, Return false
61158 * to cancel the change. The edit event object has the following properties <br />
61159 * <ul style="padding:5px;padding-left:16px;">
61160 * <li>editor - This editor</li>
61161 * <li>grid - This grid</li>
61162 * <li>record - The record being edited</li>
61163 * <li>field - The field name being edited</li>
61164 * <li>value - The value being set</li>
61165 * <li>originalValue - The original value for the field, before the edit.</li>
61166 * <li>row - The grid row index</li>
61167 * <li>column - The grid column index</li>
61168 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
61170 * @param {Object} e An edit event (see above for description)
61172 "validateedit" : true
61174 this.on("bodyscroll", this.stopEditing, this);
61175 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
61178 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
61180 * @cfg {Number} clicksToEdit
61181 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
61188 trackMouseOver: false, // causes very odd FF errors
61190 onCellDblClick : function(g, row, col){
61191 this.startEditing(row, col);
61194 onEditComplete : function(ed, value, startValue){
61195 this.editing = false;
61196 this.activeEditor = null;
61197 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
61199 var field = this.colModel.getDataIndex(ed.col);
61204 originalValue: startValue,
61211 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
61214 if(String(value) !== String(startValue)){
61216 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
61217 r.set(field, e.value);
61218 // if we are dealing with a combo box..
61219 // then we also set the 'name' colum to be the displayField
61220 if (ed.field.displayField && ed.field.name) {
61221 r.set(ed.field.name, ed.field.el.dom.value);
61224 delete e.cancel; //?? why!!!
61225 this.fireEvent("afteredit", e);
61228 this.fireEvent("afteredit", e); // always fire it!
61230 this.view.focusCell(ed.row, ed.col);
61234 * Starts editing the specified for the specified row/column
61235 * @param {Number} rowIndex
61236 * @param {Number} colIndex
61238 startEditing : function(row, col){
61239 this.stopEditing();
61240 if(this.colModel.isCellEditable(col, row)){
61241 this.view.ensureVisible(row, col, true);
61243 var r = this.dataSource.getAt(row);
61244 var field = this.colModel.getDataIndex(col);
61245 var cell = Roo.get(this.view.getCell(row,col));
61250 value: r.data[field],
61255 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
61256 this.editing = true;
61257 var ed = this.colModel.getCellEditor(col, row);
61263 ed.render(ed.parentEl || document.body);
61269 (function(){ // complex but required for focus issues in safari, ie and opera
61273 ed.on("complete", this.onEditComplete, this, {single: true});
61274 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
61275 this.activeEditor = ed;
61276 var v = r.data[field];
61277 ed.startEdit(this.view.getCell(row, col), v);
61278 // combo's with 'displayField and name set
61279 if (ed.field.displayField && ed.field.name) {
61280 ed.field.el.dom.value = r.data[ed.field.name];
61284 }).defer(50, this);
61290 * Stops any active editing
61292 stopEditing : function(){
61293 if(this.activeEditor){
61294 this.activeEditor.completeEdit();
61296 this.activeEditor = null;
61300 * Called to get grid's drag proxy text, by default returns this.ddText.
61303 getDragDropText : function(){
61304 var count = this.selModel.getSelectedCell() ? 1 : 0;
61305 return String.format(this.ddText, count, count == 1 ? '' : 's');
61310 * Ext JS Library 1.1.1
61311 * Copyright(c) 2006-2007, Ext JS, LLC.
61313 * Originally Released Under LGPL - original licence link has changed is not relivant.
61316 * <script type="text/javascript">
61319 // private - not really -- you end up using it !
61320 // This is a support class used internally by the Grid components
61323 * @class Roo.grid.GridEditor
61324 * @extends Roo.Editor
61325 * Class for creating and editable grid elements.
61326 * @param {Object} config any settings (must include field)
61328 Roo.grid.GridEditor = function(field, config){
61329 if (!config && field.field) {
61331 field = Roo.factory(config.field, Roo.form);
61333 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
61334 field.monitorTab = false;
61337 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
61340 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
61343 alignment: "tl-tl",
61346 cls: "x-small-editor x-grid-editor",
61351 * Ext JS Library 1.1.1
61352 * Copyright(c) 2006-2007, Ext JS, LLC.
61354 * Originally Released Under LGPL - original licence link has changed is not relivant.
61357 * <script type="text/javascript">
61362 Roo.grid.PropertyRecord = Roo.data.Record.create([
61363 {name:'name',type:'string'}, 'value'
61367 Roo.grid.PropertyStore = function(grid, source){
61369 this.store = new Roo.data.Store({
61370 recordType : Roo.grid.PropertyRecord
61372 this.store.on('update', this.onUpdate, this);
61374 this.setSource(source);
61376 Roo.grid.PropertyStore.superclass.constructor.call(this);
61381 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
61382 setSource : function(o){
61384 this.store.removeAll();
61387 if(this.isEditableValue(o[k])){
61388 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
61391 this.store.loadRecords({records: data}, {}, true);
61394 onUpdate : function(ds, record, type){
61395 if(type == Roo.data.Record.EDIT){
61396 var v = record.data['value'];
61397 var oldValue = record.modified['value'];
61398 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
61399 this.source[record.id] = v;
61401 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
61408 getProperty : function(row){
61409 return this.store.getAt(row);
61412 isEditableValue: function(val){
61413 if(val && val instanceof Date){
61415 }else if(typeof val == 'object' || typeof val == 'function'){
61421 setValue : function(prop, value){
61422 this.source[prop] = value;
61423 this.store.getById(prop).set('value', value);
61426 getSource : function(){
61427 return this.source;
61431 Roo.grid.PropertyColumnModel = function(grid, store){
61434 g.PropertyColumnModel.superclass.constructor.call(this, [
61435 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
61436 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
61438 this.store = store;
61439 this.bselect = Roo.DomHelper.append(document.body, {
61440 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
61441 {tag: 'option', value: 'true', html: 'true'},
61442 {tag: 'option', value: 'false', html: 'false'}
61445 Roo.id(this.bselect);
61448 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
61449 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
61450 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
61451 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
61452 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
61454 this.renderCellDelegate = this.renderCell.createDelegate(this);
61455 this.renderPropDelegate = this.renderProp.createDelegate(this);
61458 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
61462 valueText : 'Value',
61464 dateFormat : 'm/j/Y',
61467 renderDate : function(dateVal){
61468 return dateVal.dateFormat(this.dateFormat);
61471 renderBool : function(bVal){
61472 return bVal ? 'true' : 'false';
61475 isCellEditable : function(colIndex, rowIndex){
61476 return colIndex == 1;
61479 getRenderer : function(col){
61481 this.renderCellDelegate : this.renderPropDelegate;
61484 renderProp : function(v){
61485 return this.getPropertyName(v);
61488 renderCell : function(val){
61490 if(val instanceof Date){
61491 rv = this.renderDate(val);
61492 }else if(typeof val == 'boolean'){
61493 rv = this.renderBool(val);
61495 return Roo.util.Format.htmlEncode(rv);
61498 getPropertyName : function(name){
61499 var pn = this.grid.propertyNames;
61500 return pn && pn[name] ? pn[name] : name;
61503 getCellEditor : function(colIndex, rowIndex){
61504 var p = this.store.getProperty(rowIndex);
61505 var n = p.data['name'], val = p.data['value'];
61507 if(typeof(this.grid.customEditors[n]) == 'string'){
61508 return this.editors[this.grid.customEditors[n]];
61510 if(typeof(this.grid.customEditors[n]) != 'undefined'){
61511 return this.grid.customEditors[n];
61513 if(val instanceof Date){
61514 return this.editors['date'];
61515 }else if(typeof val == 'number'){
61516 return this.editors['number'];
61517 }else if(typeof val == 'boolean'){
61518 return this.editors['boolean'];
61520 return this.editors['string'];
61526 * @class Roo.grid.PropertyGrid
61527 * @extends Roo.grid.EditorGrid
61528 * This class represents the interface of a component based property grid control.
61529 * <br><br>Usage:<pre><code>
61530 var grid = new Roo.grid.PropertyGrid("my-container-id", {
61538 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
61539 * The container MUST have some type of size defined for the grid to fill. The container will be
61540 * automatically set to position relative if it isn't already.
61541 * @param {Object} config A config object that sets properties on this grid.
61543 Roo.grid.PropertyGrid = function(container, config){
61544 config = config || {};
61545 var store = new Roo.grid.PropertyStore(this);
61546 this.store = store;
61547 var cm = new Roo.grid.PropertyColumnModel(this, store);
61548 store.store.sort('name', 'ASC');
61549 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
61552 enableColLock:false,
61553 enableColumnMove:false,
61555 trackMouseOver: false,
61558 this.getGridEl().addClass('x-props-grid');
61559 this.lastEditRow = null;
61560 this.on('columnresize', this.onColumnResize, this);
61563 * @event beforepropertychange
61564 * Fires before a property changes (return false to stop?)
61565 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
61566 * @param {String} id Record Id
61567 * @param {String} newval New Value
61568 * @param {String} oldval Old Value
61570 "beforepropertychange": true,
61572 * @event propertychange
61573 * Fires after a property changes
61574 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
61575 * @param {String} id Record Id
61576 * @param {String} newval New Value
61577 * @param {String} oldval Old Value
61579 "propertychange": true
61581 this.customEditors = this.customEditors || {};
61583 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
61586 * @cfg {Object} customEditors map of colnames=> custom editors.
61587 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
61588 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
61589 * false disables editing of the field.
61593 * @cfg {Object} propertyNames map of property Names to their displayed value
61596 render : function(){
61597 Roo.grid.PropertyGrid.superclass.render.call(this);
61598 this.autoSize.defer(100, this);
61601 autoSize : function(){
61602 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
61604 this.view.fitColumns();
61608 onColumnResize : function(){
61609 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
61613 * Sets the data for the Grid
61614 * accepts a Key => Value object of all the elements avaiable.
61615 * @param {Object} data to appear in grid.
61617 setSource : function(source){
61618 this.store.setSource(source);
61622 * Gets all the data from the grid.
61623 * @return {Object} data data stored in grid
61625 getSource : function(){
61626 return this.store.getSource();
61635 * @class Roo.grid.Calendar
61636 * @extends Roo.grid.Grid
61637 * This class extends the Grid to provide a calendar widget
61638 * <br><br>Usage:<pre><code>
61639 var grid = new Roo.grid.Calendar("my-container-id", {
61642 selModel: mySelectionModel,
61643 autoSizeColumns: true,
61644 monitorWindowResize: false,
61645 trackMouseOver: true
61646 eventstore : real data store..
61652 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
61653 * The container MUST have some type of size defined for the grid to fill. The container will be
61654 * automatically set to position relative if it isn't already.
61655 * @param {Object} config A config object that sets properties on this grid.
61657 Roo.grid.Calendar = function(container, config){
61658 // initialize the container
61659 this.container = Roo.get(container);
61660 this.container.update("");
61661 this.container.setStyle("overflow", "hidden");
61662 this.container.addClass('x-grid-container');
61664 this.id = this.container.id;
61666 Roo.apply(this, config);
61667 // check and correct shorthanded configs
61671 for (var r = 0;r < 6;r++) {
61674 for (var c =0;c < 7;c++) {
61678 if (this.eventStore) {
61679 this.eventStore= Roo.factory(this.eventStore, Roo.data);
61680 this.eventStore.on('load',this.onLoad, this);
61681 this.eventStore.on('beforeload',this.clearEvents, this);
61685 this.dataSource = new Roo.data.Store({
61686 proxy: new Roo.data.MemoryProxy(rows),
61687 reader: new Roo.data.ArrayReader({}, [
61688 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
61691 this.dataSource.load();
61692 this.ds = this.dataSource;
61693 this.ds.xmodule = this.xmodule || false;
61696 var cellRender = function(v,x,r)
61698 return String.format(
61699 '<div class="fc-day fc-widget-content"><div>' +
61700 '<div class="fc-event-container"></div>' +
61701 '<div class="fc-day-number">{0}</div>'+
61703 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
61704 '</div></div>', v);
61709 this.colModel = new Roo.grid.ColumnModel( [
61711 xtype: 'ColumnModel',
61713 dataIndex : 'weekday0',
61715 renderer : cellRender
61718 xtype: 'ColumnModel',
61720 dataIndex : 'weekday1',
61722 renderer : cellRender
61725 xtype: 'ColumnModel',
61727 dataIndex : 'weekday2',
61728 header : 'Tuesday',
61729 renderer : cellRender
61732 xtype: 'ColumnModel',
61734 dataIndex : 'weekday3',
61735 header : 'Wednesday',
61736 renderer : cellRender
61739 xtype: 'ColumnModel',
61741 dataIndex : 'weekday4',
61742 header : 'Thursday',
61743 renderer : cellRender
61746 xtype: 'ColumnModel',
61748 dataIndex : 'weekday5',
61750 renderer : cellRender
61753 xtype: 'ColumnModel',
61755 dataIndex : 'weekday6',
61756 header : 'Saturday',
61757 renderer : cellRender
61760 this.cm = this.colModel;
61761 this.cm.xmodule = this.xmodule || false;
61765 //this.selModel = new Roo.grid.CellSelectionModel();
61766 //this.sm = this.selModel;
61767 //this.selModel.init(this);
61771 this.container.setWidth(this.width);
61775 this.container.setHeight(this.height);
61782 * The raw click event for the entire grid.
61783 * @param {Roo.EventObject} e
61788 * The raw dblclick event for the entire grid.
61789 * @param {Roo.EventObject} e
61793 * @event contextmenu
61794 * The raw contextmenu event for the entire grid.
61795 * @param {Roo.EventObject} e
61797 "contextmenu" : true,
61800 * The raw mousedown event for the entire grid.
61801 * @param {Roo.EventObject} e
61803 "mousedown" : true,
61806 * The raw mouseup event for the entire grid.
61807 * @param {Roo.EventObject} e
61812 * The raw mouseover event for the entire grid.
61813 * @param {Roo.EventObject} e
61815 "mouseover" : true,
61818 * The raw mouseout event for the entire grid.
61819 * @param {Roo.EventObject} e
61824 * The raw keypress event for the entire grid.
61825 * @param {Roo.EventObject} e
61830 * The raw keydown event for the entire grid.
61831 * @param {Roo.EventObject} e
61839 * Fires when a cell is clicked
61840 * @param {Grid} this
61841 * @param {Number} rowIndex
61842 * @param {Number} columnIndex
61843 * @param {Roo.EventObject} e
61845 "cellclick" : true,
61847 * @event celldblclick
61848 * Fires when a cell is double clicked
61849 * @param {Grid} this
61850 * @param {Number} rowIndex
61851 * @param {Number} columnIndex
61852 * @param {Roo.EventObject} e
61854 "celldblclick" : true,
61857 * Fires when a row is clicked
61858 * @param {Grid} this
61859 * @param {Number} rowIndex
61860 * @param {Roo.EventObject} e
61864 * @event rowdblclick
61865 * Fires when a row is double clicked
61866 * @param {Grid} this
61867 * @param {Number} rowIndex
61868 * @param {Roo.EventObject} e
61870 "rowdblclick" : true,
61872 * @event headerclick
61873 * Fires when a header is clicked
61874 * @param {Grid} this
61875 * @param {Number} columnIndex
61876 * @param {Roo.EventObject} e
61878 "headerclick" : true,
61880 * @event headerdblclick
61881 * Fires when a header cell is double clicked
61882 * @param {Grid} this
61883 * @param {Number} columnIndex
61884 * @param {Roo.EventObject} e
61886 "headerdblclick" : true,
61888 * @event rowcontextmenu
61889 * Fires when a row is right clicked
61890 * @param {Grid} this
61891 * @param {Number} rowIndex
61892 * @param {Roo.EventObject} e
61894 "rowcontextmenu" : true,
61896 * @event cellcontextmenu
61897 * Fires when a cell is right clicked
61898 * @param {Grid} this
61899 * @param {Number} rowIndex
61900 * @param {Number} cellIndex
61901 * @param {Roo.EventObject} e
61903 "cellcontextmenu" : true,
61905 * @event headercontextmenu
61906 * Fires when a header is right clicked
61907 * @param {Grid} this
61908 * @param {Number} columnIndex
61909 * @param {Roo.EventObject} e
61911 "headercontextmenu" : true,
61913 * @event bodyscroll
61914 * Fires when the body element is scrolled
61915 * @param {Number} scrollLeft
61916 * @param {Number} scrollTop
61918 "bodyscroll" : true,
61920 * @event columnresize
61921 * Fires when the user resizes a column
61922 * @param {Number} columnIndex
61923 * @param {Number} newSize
61925 "columnresize" : true,
61927 * @event columnmove
61928 * Fires when the user moves a column
61929 * @param {Number} oldIndex
61930 * @param {Number} newIndex
61932 "columnmove" : true,
61935 * Fires when row(s) start being dragged
61936 * @param {Grid} this
61937 * @param {Roo.GridDD} dd The drag drop object
61938 * @param {event} e The raw browser event
61940 "startdrag" : true,
61943 * Fires when a drag operation is complete
61944 * @param {Grid} this
61945 * @param {Roo.GridDD} dd The drag drop object
61946 * @param {event} e The raw browser event
61951 * Fires when dragged row(s) are dropped on a valid DD target
61952 * @param {Grid} this
61953 * @param {Roo.GridDD} dd The drag drop object
61954 * @param {String} targetId The target drag drop object
61955 * @param {event} e The raw browser event
61960 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
61961 * @param {Grid} this
61962 * @param {Roo.GridDD} dd The drag drop object
61963 * @param {String} targetId The target drag drop object
61964 * @param {event} e The raw browser event
61969 * Fires when the dragged row(s) first cross another DD target while being dragged
61970 * @param {Grid} this
61971 * @param {Roo.GridDD} dd The drag drop object
61972 * @param {String} targetId The target drag drop object
61973 * @param {event} e The raw browser event
61975 "dragenter" : true,
61978 * Fires when the dragged row(s) leave another DD target while being dragged
61979 * @param {Grid} this
61980 * @param {Roo.GridDD} dd The drag drop object
61981 * @param {String} targetId The target drag drop object
61982 * @param {event} e The raw browser event
61987 * Fires when a row is rendered, so you can change add a style to it.
61988 * @param {GridView} gridview The grid view
61989 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
61995 * Fires when the grid is rendered
61996 * @param {Grid} grid
62001 * Fires when a date is selected
62002 * @param {DatePicker} this
62003 * @param {Date} date The selected date
62007 * @event monthchange
62008 * Fires when the displayed month changes
62009 * @param {DatePicker} this
62010 * @param {Date} date The selected month
62012 'monthchange': true,
62014 * @event evententer
62015 * Fires when mouse over an event
62016 * @param {Calendar} this
62017 * @param {event} Event
62019 'evententer': true,
62021 * @event eventleave
62022 * Fires when the mouse leaves an
62023 * @param {Calendar} this
62026 'eventleave': true,
62028 * @event eventclick
62029 * Fires when the mouse click an
62030 * @param {Calendar} this
62033 'eventclick': true,
62035 * @event eventrender
62036 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
62037 * @param {Calendar} this
62038 * @param {data} data to be modified
62040 'eventrender': true
62044 Roo.grid.Grid.superclass.constructor.call(this);
62045 this.on('render', function() {
62046 this.view.el.addClass('x-grid-cal');
62048 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
62052 if (!Roo.grid.Calendar.style) {
62053 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
62056 '.x-grid-cal .x-grid-col' : {
62057 height: 'auto !important',
62058 'vertical-align': 'top'
62060 '.x-grid-cal .fc-event-hori' : {
62071 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
62073 * @cfg {Store} eventStore The store that loads events.
62078 activeDate : false,
62081 monitorWindowResize : false,
62084 resizeColumns : function() {
62085 var col = (this.view.el.getWidth() / 7) - 3;
62086 // loop through cols, and setWidth
62087 for(var i =0 ; i < 7 ; i++){
62088 this.cm.setColumnWidth(i, col);
62091 setDate :function(date) {
62093 Roo.log('setDate?');
62095 this.resizeColumns();
62096 var vd = this.activeDate;
62097 this.activeDate = date;
62098 // if(vd && this.el){
62099 // var t = date.getTime();
62100 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
62101 // Roo.log('using add remove');
62103 // this.fireEvent('monthchange', this, date);
62105 // this.cells.removeClass("fc-state-highlight");
62106 // this.cells.each(function(c){
62107 // if(c.dateValue == t){
62108 // c.addClass("fc-state-highlight");
62109 // setTimeout(function(){
62110 // try{c.dom.firstChild.focus();}catch(e){}
62120 var days = date.getDaysInMonth();
62122 var firstOfMonth = date.getFirstDateOfMonth();
62123 var startingPos = firstOfMonth.getDay()-this.startDay;
62125 if(startingPos < this.startDay){
62129 var pm = date.add(Date.MONTH, -1);
62130 var prevStart = pm.getDaysInMonth()-startingPos;
62134 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
62136 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
62137 //this.cells.addClassOnOver('fc-state-hover');
62139 var cells = this.cells.elements;
62140 var textEls = this.textNodes;
62142 //Roo.each(cells, function(cell){
62143 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
62146 days += startingPos;
62148 // convert everything to numbers so it's fast
62149 var day = 86400000;
62150 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
62153 //Roo.log(prevStart);
62155 var today = new Date().clearTime().getTime();
62156 var sel = date.clearTime().getTime();
62157 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
62158 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
62159 var ddMatch = this.disabledDatesRE;
62160 var ddText = this.disabledDatesText;
62161 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
62162 var ddaysText = this.disabledDaysText;
62163 var format = this.format;
62165 var setCellClass = function(cal, cell){
62167 //Roo.log('set Cell Class');
62169 var t = d.getTime();
62174 cell.dateValue = t;
62176 cell.className += " fc-today";
62177 cell.className += " fc-state-highlight";
62178 cell.title = cal.todayText;
62181 // disable highlight in other month..
62182 cell.className += " fc-state-highlight";
62187 //cell.className = " fc-state-disabled";
62188 cell.title = cal.minText;
62192 //cell.className = " fc-state-disabled";
62193 cell.title = cal.maxText;
62197 if(ddays.indexOf(d.getDay()) != -1){
62198 // cell.title = ddaysText;
62199 // cell.className = " fc-state-disabled";
62202 if(ddMatch && format){
62203 var fvalue = d.dateFormat(format);
62204 if(ddMatch.test(fvalue)){
62205 cell.title = ddText.replace("%0", fvalue);
62206 cell.className = " fc-state-disabled";
62210 if (!cell.initialClassName) {
62211 cell.initialClassName = cell.dom.className;
62214 cell.dom.className = cell.initialClassName + ' ' + cell.className;
62219 for(; i < startingPos; i++) {
62220 cells[i].dayName = (++prevStart);
62221 Roo.log(textEls[i]);
62222 d.setDate(d.getDate()+1);
62224 //cells[i].className = "fc-past fc-other-month";
62225 setCellClass(this, cells[i]);
62230 for(; i < days; i++){
62231 intDay = i - startingPos + 1;
62232 cells[i].dayName = (intDay);
62233 d.setDate(d.getDate()+1);
62235 cells[i].className = ''; // "x-date-active";
62236 setCellClass(this, cells[i]);
62240 for(; i < 42; i++) {
62241 //textEls[i].innerHTML = (++extraDays);
62243 d.setDate(d.getDate()+1);
62244 cells[i].dayName = (++extraDays);
62245 cells[i].className = "fc-future fc-other-month";
62246 setCellClass(this, cells[i]);
62249 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
62251 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
62253 // this will cause all the cells to mis
62256 for (var r = 0;r < 6;r++) {
62257 for (var c =0;c < 7;c++) {
62258 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
62262 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
62263 for(i=0;i<cells.length;i++) {
62265 this.cells.elements[i].dayName = cells[i].dayName ;
62266 this.cells.elements[i].className = cells[i].className;
62267 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
62268 this.cells.elements[i].title = cells[i].title ;
62269 this.cells.elements[i].dateValue = cells[i].dateValue ;
62275 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
62276 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
62278 ////if(totalRows != 6){
62279 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
62280 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
62283 this.fireEvent('monthchange', this, date);
62288 * Returns the grid's SelectionModel.
62289 * @return {SelectionModel}
62291 getSelectionModel : function(){
62292 if(!this.selModel){
62293 this.selModel = new Roo.grid.CellSelectionModel();
62295 return this.selModel;
62299 this.eventStore.load()
62305 findCell : function(dt) {
62306 dt = dt.clearTime().getTime();
62308 this.cells.each(function(c){
62309 //Roo.log("check " +c.dateValue + '?=' + dt);
62310 if(c.dateValue == dt){
62320 findCells : function(rec) {
62321 var s = rec.data.start_dt.clone().clearTime().getTime();
62323 var e= rec.data.end_dt.clone().clearTime().getTime();
62326 this.cells.each(function(c){
62327 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
62329 if(c.dateValue > e){
62332 if(c.dateValue < s){
62341 findBestRow: function(cells)
62345 for (var i =0 ; i < cells.length;i++) {
62346 ret = Math.max(cells[i].rows || 0,ret);
62353 addItem : function(rec)
62355 // look for vertical location slot in
62356 var cells = this.findCells(rec);
62358 rec.row = this.findBestRow(cells);
62360 // work out the location.
62364 for(var i =0; i < cells.length; i++) {
62372 if (crow.start.getY() == cells[i].getY()) {
62374 crow.end = cells[i];
62390 for (var i = 0; i < cells.length;i++) {
62391 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
62398 clearEvents: function() {
62400 if (!this.eventStore.getCount()) {
62403 // reset number of rows in cells.
62404 Roo.each(this.cells.elements, function(c){
62408 this.eventStore.each(function(e) {
62409 this.clearEvent(e);
62414 clearEvent : function(ev)
62417 Roo.each(ev.els, function(el) {
62418 el.un('mouseenter' ,this.onEventEnter, this);
62419 el.un('mouseleave' ,this.onEventLeave, this);
62427 renderEvent : function(ev,ctr) {
62429 ctr = this.view.el.select('.fc-event-container',true).first();
62433 this.clearEvent(ev);
62439 var cells = ev.cells;
62440 var rows = ev.rows;
62441 this.fireEvent('eventrender', this, ev);
62443 for(var i =0; i < rows.length; i++) {
62447 cls += ' fc-event-start';
62449 if ((i+1) == rows.length) {
62450 cls += ' fc-event-end';
62453 //Roo.log(ev.data);
62454 // how many rows should it span..
62455 var cg = this.eventTmpl.append(ctr,Roo.apply({
62458 }, ev.data) , true);
62461 cg.on('mouseenter' ,this.onEventEnter, this, ev);
62462 cg.on('mouseleave' ,this.onEventLeave, this, ev);
62463 cg.on('click', this.onEventClick, this, ev);
62467 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
62468 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
62471 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
62472 cg.setWidth(ebox.right - sbox.x -2);
62476 renderEvents: function()
62478 // first make sure there is enough space..
62480 if (!this.eventTmpl) {
62481 this.eventTmpl = new Roo.Template(
62482 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
62483 '<div class="fc-event-inner">' +
62484 '<span class="fc-event-time">{time}</span>' +
62485 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
62487 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
62495 this.cells.each(function(c) {
62496 //Roo.log(c.select('.fc-day-content div',true).first());
62497 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
62500 var ctr = this.view.el.select('.fc-event-container',true).first();
62503 this.eventStore.each(function(ev){
62505 this.renderEvent(ev);
62509 this.view.layout();
62513 onEventEnter: function (e, el,event,d) {
62514 this.fireEvent('evententer', this, el, event);
62517 onEventLeave: function (e, el,event,d) {
62518 this.fireEvent('eventleave', this, el, event);
62521 onEventClick: function (e, el,event,d) {
62522 this.fireEvent('eventclick', this, el, event);
62525 onMonthChange: function () {
62529 onLoad: function () {
62531 //Roo.log('calendar onload');
62533 if(this.eventStore.getCount() > 0){
62537 this.eventStore.each(function(d){
62542 if (typeof(add.end_dt) == 'undefined') {
62543 Roo.log("Missing End time in calendar data: ");
62547 if (typeof(add.start_dt) == 'undefined') {
62548 Roo.log("Missing Start time in calendar data: ");
62552 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
62553 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
62554 add.id = add.id || d.id;
62555 add.title = add.title || '??';
62563 this.renderEvents();
62573 render : function ()
62577 if (!this.view.el.hasClass('course-timesheet')) {
62578 this.view.el.addClass('course-timesheet');
62580 if (this.tsStyle) {
62585 Roo.log(_this.grid.view.el.getWidth());
62588 this.tsStyle = Roo.util.CSS.createStyleSheet({
62589 '.course-timesheet .x-grid-row' : {
62592 '.x-grid-row td' : {
62593 'vertical-align' : 0
62595 '.course-edit-link' : {
62597 'text-overflow' : 'ellipsis',
62598 'overflow' : 'hidden',
62599 'white-space' : 'nowrap',
62600 'cursor' : 'pointer'
62605 '.de-act-sup-link' : {
62606 'color' : 'purple',
62607 'text-decoration' : 'line-through'
62611 'text-decoration' : 'line-through'
62613 '.course-timesheet .course-highlight' : {
62614 'border-top-style': 'dashed !important',
62615 'border-bottom-bottom': 'dashed !important'
62617 '.course-timesheet .course-item' : {
62618 'font-family' : 'tahoma, arial, helvetica',
62619 'font-size' : '11px',
62620 'overflow' : 'hidden',
62621 'padding-left' : '10px',
62622 'padding-right' : '10px',
62623 'padding-top' : '10px'
62631 monitorWindowResize : false,
62632 cellrenderer : function(v,x,r)
62637 xtype: 'CellSelectionModel',
62644 beforeload : function (_self, options)
62646 options.params = options.params || {};
62647 options.params._month = _this.monthField.getValue();
62648 options.params.limit = 9999;
62649 options.params['sort'] = 'when_dt';
62650 options.params['dir'] = 'ASC';
62651 this.proxy.loadResponse = this.loadResponse;
62653 //this.addColumns();
62655 load : function (_self, records, options)
62657 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
62658 // if you click on the translation.. you can edit it...
62659 var el = Roo.get(this);
62660 var id = el.dom.getAttribute('data-id');
62661 var d = el.dom.getAttribute('data-date');
62662 var t = el.dom.getAttribute('data-time');
62663 //var id = this.child('span').dom.textContent;
62666 Pman.Dialog.CourseCalendar.show({
62670 productitem_active : id ? 1 : 0
62672 _this.grid.ds.load({});
62677 _this.panel.fireEvent('resize', [ '', '' ]);
62680 loadResponse : function(o, success, response){
62681 // this is overridden on before load..
62683 Roo.log("our code?");
62684 //Roo.log(success);
62685 //Roo.log(response)
62686 delete this.activeRequest;
62688 this.fireEvent("loadexception", this, o, response);
62689 o.request.callback.call(o.request.scope, null, o.request.arg, false);
62694 result = o.reader.read(response);
62696 Roo.log("load exception?");
62697 this.fireEvent("loadexception", this, o, response, e);
62698 o.request.callback.call(o.request.scope, null, o.request.arg, false);
62701 Roo.log("ready...");
62702 // loop through result.records;
62703 // and set this.tdate[date] = [] << array of records..
62705 Roo.each(result.records, function(r){
62707 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
62708 _this.tdata[r.data.when_dt.format('j')] = [];
62710 _this.tdata[r.data.when_dt.format('j')].push(r.data);
62713 //Roo.log(_this.tdata);
62715 result.records = [];
62716 result.totalRecords = 6;
62718 // let's generate some duumy records for the rows.
62719 //var st = _this.dateField.getValue();
62721 // work out monday..
62722 //st = st.add(Date.DAY, -1 * st.format('w'));
62724 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
62726 var firstOfMonth = date.getFirstDayOfMonth();
62727 var days = date.getDaysInMonth();
62729 var firstAdded = false;
62730 for (var i = 0; i < result.totalRecords ; i++) {
62731 //var d= st.add(Date.DAY, i);
62734 for(var w = 0 ; w < 7 ; w++){
62735 if(!firstAdded && firstOfMonth != w){
62742 var dd = (d > 0 && d < 10) ? "0"+d : d;
62743 row['weekday'+w] = String.format(
62744 '<span style="font-size: 16px;"><b>{0}</b></span>'+
62745 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
62747 date.format('Y-m-')+dd
62750 if(typeof(_this.tdata[d]) != 'undefined'){
62751 Roo.each(_this.tdata[d], function(r){
62755 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
62756 if(r.parent_id*1>0){
62757 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
62760 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
62761 deactive = 'de-act-link';
62764 row['weekday'+w] += String.format(
62765 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
62767 r.product_id_name, //1
62768 r.when_dt.format('h:ia'), //2
62778 // only do this if something added..
62780 result.records.push(_this.grid.dataSource.reader.newRow(row));
62784 // push it twice. (second one with an hour..
62788 this.fireEvent("load", this, o, o.request.arg);
62789 o.request.callback.call(o.request.scope, result, o.request.arg, true);
62791 sortInfo : {field: 'when_dt', direction : 'ASC' },
62793 xtype: 'HttpProxy',
62796 url : baseURL + '/Roo/Shop_course.php'
62799 xtype: 'JsonReader',
62816 'name': 'parent_id',
62820 'name': 'product_id',
62824 'name': 'productitem_id',
62842 click : function (_self, e)
62844 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
62845 sd.setMonth(sd.getMonth()-1);
62846 _this.monthField.setValue(sd.format('Y-m-d'));
62847 _this.grid.ds.load({});
62853 xtype: 'Separator',
62857 xtype: 'MonthField',
62860 render : function (_self)
62862 _this.monthField = _self;
62863 // _this.monthField.set today
62865 select : function (combo, date)
62867 _this.grid.ds.load({});
62870 value : (function() { return new Date(); })()
62873 xtype: 'Separator',
62879 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
62889 click : function (_self, e)
62891 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
62892 sd.setMonth(sd.getMonth()+1);
62893 _this.monthField.setValue(sd.format('Y-m-d'));
62894 _this.grid.ds.load({});
62907 * Ext JS Library 1.1.1
62908 * Copyright(c) 2006-2007, Ext JS, LLC.
62910 * Originally Released Under LGPL - original licence link has changed is not relivant.
62913 * <script type="text/javascript">
62917 * @class Roo.LoadMask
62918 * A simple utility class for generically masking elements while loading data. If the element being masked has
62919 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
62920 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
62921 * element's UpdateManager load indicator and will be destroyed after the initial load.
62923 * Create a new LoadMask
62924 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
62925 * @param {Object} config The config object
62927 Roo.LoadMask = function(el, config){
62928 this.el = Roo.get(el);
62929 Roo.apply(this, config);
62931 this.store.on('beforeload', this.onBeforeLoad, this);
62932 this.store.on('load', this.onLoad, this);
62933 this.store.on('loadexception', this.onLoadException, this);
62934 this.removeMask = false;
62936 var um = this.el.getUpdateManager();
62937 um.showLoadIndicator = false; // disable the default indicator
62938 um.on('beforeupdate', this.onBeforeLoad, this);
62939 um.on('update', this.onLoad, this);
62940 um.on('failure', this.onLoad, this);
62941 this.removeMask = true;
62945 Roo.LoadMask.prototype = {
62947 * @cfg {Boolean} removeMask
62948 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
62949 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
62951 removeMask : false,
62953 * @cfg {String} msg
62954 * The text to display in a centered loading message box (defaults to 'Loading...')
62956 msg : 'Loading...',
62958 * @cfg {String} msgCls
62959 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
62961 msgCls : 'x-mask-loading',
62964 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
62970 * Disables the mask to prevent it from being displayed
62972 disable : function(){
62973 this.disabled = true;
62977 * Enables the mask so that it can be displayed
62979 enable : function(){
62980 this.disabled = false;
62983 onLoadException : function()
62985 Roo.log(arguments);
62987 if (typeof(arguments[3]) != 'undefined') {
62988 Roo.MessageBox.alert("Error loading",arguments[3]);
62992 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
62993 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
63000 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
63003 onLoad : function()
63005 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
63009 onBeforeLoad : function(){
63010 if(!this.disabled){
63011 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
63016 destroy : function(){
63018 this.store.un('beforeload', this.onBeforeLoad, this);
63019 this.store.un('load', this.onLoad, this);
63020 this.store.un('loadexception', this.onLoadException, this);
63022 var um = this.el.getUpdateManager();
63023 um.un('beforeupdate', this.onBeforeLoad, this);
63024 um.un('update', this.onLoad, this);
63025 um.un('failure', this.onLoad, this);
63030 * Ext JS Library 1.1.1
63031 * Copyright(c) 2006-2007, Ext JS, LLC.
63033 * Originally Released Under LGPL - original licence link has changed is not relivant.
63036 * <script type="text/javascript">
63041 * @class Roo.XTemplate
63042 * @extends Roo.Template
63043 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
63045 var t = new Roo.XTemplate(
63046 '<select name="{name}">',
63047 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
63051 // then append, applying the master template values
63054 * Supported features:
63059 {a_variable} - output encoded.
63060 {a_variable.format:("Y-m-d")} - call a method on the variable
63061 {a_variable:raw} - unencoded output
63062 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
63063 {a_variable:this.method_on_template(...)} - call a method on the template object.
63068 <tpl for="a_variable or condition.."></tpl>
63069 <tpl if="a_variable or condition"></tpl>
63070 <tpl exec="some javascript"></tpl>
63071 <tpl name="named_template"></tpl> (experimental)
63073 <tpl for="."></tpl> - just iterate the property..
63074 <tpl for=".."></tpl> - iterates with the parent (probably the template)
63078 Roo.XTemplate = function()
63080 Roo.XTemplate.superclass.constructor.apply(this, arguments);
63087 Roo.extend(Roo.XTemplate, Roo.Template, {
63090 * The various sub templates
63095 * basic tag replacing syntax
63098 * // you can fake an object call by doing this
63102 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
63105 * compile the template
63107 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
63110 compile: function()
63114 s = ['<tpl>', s, '</tpl>'].join('');
63116 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
63117 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
63118 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
63119 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
63120 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
63125 while(true == !!(m = s.match(re))){
63126 var forMatch = m[0].match(nameRe),
63127 ifMatch = m[0].match(ifRe),
63128 execMatch = m[0].match(execRe),
63129 namedMatch = m[0].match(namedRe),
63134 name = forMatch && forMatch[1] ? forMatch[1] : '';
63137 // if - puts fn into test..
63138 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
63140 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
63145 // exec - calls a function... returns empty if true is returned.
63146 exp = execMatch && execMatch[1] ? execMatch[1] : null;
63148 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
63156 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
63157 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
63158 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
63161 var uid = namedMatch ? namedMatch[1] : id;
63165 id: namedMatch ? namedMatch[1] : id,
63172 s = s.replace(m[0], '');
63174 s = s.replace(m[0], '{xtpl'+ id + '}');
63179 for(var i = tpls.length-1; i >= 0; --i){
63180 this.compileTpl(tpls[i]);
63181 this.tpls[tpls[i].id] = tpls[i];
63183 this.master = tpls[tpls.length-1];
63187 * same as applyTemplate, except it's done to one of the subTemplates
63188 * when using named templates, you can do:
63190 * var str = pl.applySubTemplate('your-name', values);
63193 * @param {Number} id of the template
63194 * @param {Object} values to apply to template
63195 * @param {Object} parent (normaly the instance of this object)
63197 applySubTemplate : function(id, values, parent)
63201 var t = this.tpls[id];
63205 if(t.test && !t.test.call(this, values, parent)){
63209 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
63210 Roo.log(e.toString());
63216 if(t.exec && t.exec.call(this, values, parent)){
63220 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
63221 Roo.log(e.toString());
63226 var vs = t.target ? t.target.call(this, values, parent) : values;
63227 parent = t.target ? values : parent;
63228 if(t.target && vs instanceof Array){
63230 for(var i = 0, len = vs.length; i < len; i++){
63231 buf[buf.length] = t.compiled.call(this, vs[i], parent);
63233 return buf.join('');
63235 return t.compiled.call(this, vs, parent);
63237 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
63238 Roo.log(e.toString());
63239 Roo.log(t.compiled);
63244 compileTpl : function(tpl)
63246 var fm = Roo.util.Format;
63247 var useF = this.disableFormats !== true;
63248 var sep = Roo.isGecko ? "+" : ",";
63249 var undef = function(str) {
63250 Roo.log("Property not found :" + str);
63254 var fn = function(m, name, format, args)
63256 //Roo.log(arguments);
63257 args = args ? args.replace(/\\'/g,"'") : args;
63258 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
63259 if (typeof(format) == 'undefined') {
63260 format= 'htmlEncode';
63262 if (format == 'raw' ) {
63266 if(name.substr(0, 4) == 'xtpl'){
63267 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
63270 // build an array of options to determine if value is undefined..
63272 // basically get 'xxxx.yyyy' then do
63273 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
63274 // (function () { Roo.log("Property not found"); return ''; })() :
63279 Roo.each(name.split('.'), function(st) {
63280 lookfor += (lookfor.length ? '.': '') + st;
63281 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
63284 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
63287 if(format && useF){
63289 args = args ? ',' + args : "";
63291 if(format.substr(0, 5) != "this."){
63292 format = "fm." + format + '(';
63294 format = 'this.call("'+ format.substr(5) + '", ';
63298 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
63302 // called with xxyx.yuu:(test,test)
63304 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
63306 // raw.. - :raw modifier..
63307 return "'"+ sep + udef_st + name + ")"+sep+"'";
63311 // branched to use + in gecko and [].join() in others
63313 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
63314 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
63317 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
63318 body.push(tpl.body.replace(/(\r\n|\n)/g,
63319 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
63320 body.push("'].join('');};};");
63321 body = body.join('');
63324 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
63326 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
63332 applyTemplate : function(values){
63333 return this.master.compiled.call(this, values, {});
63334 //var s = this.subs;
63337 apply : function(){
63338 return this.applyTemplate.apply(this, arguments);
63343 Roo.XTemplate.from = function(el){
63344 el = Roo.getDom(el);
63345 return new Roo.XTemplate(el.value || el.innerHTML);