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 * Ext JS Library 1.1.1
1076 * Copyright(c) 2006-2007, Ext JS, LLC.
1078 * Originally Released Under LGPL - original licence link has changed is not relivant.
1081 * <script type="text/javascript">
1087 * The date parsing and format syntax is a subset of
1088 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1089 * supported will provide results equivalent to their PHP versions.
1091 * Following is the list of all currently supported formats:
1094 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1096 Format Output Description
1097 ------ ---------- --------------------------------------------------------------
1098 d 10 Day of the month, 2 digits with leading zeros
1099 D Wed A textual representation of a day, three letters
1100 j 10 Day of the month without leading zeros
1101 l Wednesday A full textual representation of the day of the week
1102 S th English ordinal day of month suffix, 2 chars (use with j)
1103 w 3 Numeric representation of the day of the week
1104 z 9 The julian date, or day of the year (0-365)
1105 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1106 F January A full textual representation of the month
1107 m 01 Numeric representation of a month, with leading zeros
1108 M Jan Month name abbreviation, three letters
1109 n 1 Numeric representation of a month, without leading zeros
1110 t 31 Number of days in the given month
1111 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1112 Y 2007 A full numeric representation of a year, 4 digits
1113 y 07 A two digit representation of a year
1114 a pm Lowercase Ante meridiem and Post meridiem
1115 A PM Uppercase Ante meridiem and Post meridiem
1116 g 3 12-hour format of an hour without leading zeros
1117 G 15 24-hour format of an hour without leading zeros
1118 h 03 12-hour format of an hour with leading zeros
1119 H 15 24-hour format of an hour with leading zeros
1120 i 05 Minutes with leading zeros
1121 s 01 Seconds, with leading zeros
1122 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1123 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1124 T CST Timezone setting of the machine running the code
1125 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1128 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1130 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1131 document.write(dt.format('Y-m-d')); //2007-01-10
1132 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1133 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
1136 * Here are some standard date/time patterns that you might find helpful. They
1137 * are not part of the source of Date.js, but to use them you can simply copy this
1138 * block of code into any script that is included after Date.js and they will also become
1139 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1142 ISO8601Long:"Y-m-d H:i:s",
1143 ISO8601Short:"Y-m-d",
1145 LongDate: "l, F d, Y",
1146 FullDateTime: "l, F d, Y g:i:s A",
1149 LongTime: "g:i:s A",
1150 SortableDateTime: "Y-m-d\\TH:i:s",
1151 UniversalSortableDateTime: "Y-m-d H:i:sO",
1158 var dt = new Date();
1159 document.write(dt.format(Date.patterns.ShortDate));
1164 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1165 * They generate precompiled functions from date formats instead of parsing and
1166 * processing the pattern every time you format a date. These functions are available
1167 * on every Date object (any javascript function).
1169 * The original article and download are here:
1170 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1177 Returns the number of milliseconds between this date and date
1178 @param {Date} date (optional) Defaults to now
1179 @return {Number} The diff in milliseconds
1180 @member Date getElapsed
1182 Date.prototype.getElapsed = function(date) {
1183 return Math.abs((date || new Date()).getTime()-this.getTime());
1185 // was in date file..
1189 Date.parseFunctions = {count:0};
1191 Date.parseRegexes = [];
1193 Date.formatFunctions = {count:0};
1196 Date.prototype.dateFormat = function(format) {
1197 if (Date.formatFunctions[format] == null) {
1198 Date.createNewFormat(format);
1200 var func = Date.formatFunctions[format];
1201 return this[func]();
1206 * Formats a date given the supplied format string
1207 * @param {String} format The format string
1208 * @return {String} The formatted date
1211 Date.prototype.format = Date.prototype.dateFormat;
1214 Date.createNewFormat = function(format) {
1215 var funcName = "format" + Date.formatFunctions.count++;
1216 Date.formatFunctions[format] = funcName;
1217 var code = "Date.prototype." + funcName + " = function(){return ";
1218 var special = false;
1220 for (var i = 0; i < format.length; ++i) {
1221 ch = format.charAt(i);
1222 if (!special && ch == "\\") {
1227 code += "'" + String.escape(ch) + "' + ";
1230 code += Date.getFormatCode(ch);
1233 /** eval:var:zzzzzzzzzzzzz */
1234 eval(code.substring(0, code.length - 3) + ";}");
1238 Date.getFormatCode = function(character) {
1239 switch (character) {
1241 return "String.leftPad(this.getDate(), 2, '0') + ";
1243 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1245 return "this.getDate() + ";
1247 return "Date.dayNames[this.getDay()] + ";
1249 return "this.getSuffix() + ";
1251 return "this.getDay() + ";
1253 return "this.getDayOfYear() + ";
1255 return "this.getWeekOfYear() + ";
1257 return "Date.monthNames[this.getMonth()] + ";
1259 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1261 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1263 return "(this.getMonth() + 1) + ";
1265 return "this.getDaysInMonth() + ";
1267 return "(this.isLeapYear() ? 1 : 0) + ";
1269 return "this.getFullYear() + ";
1271 return "('' + this.getFullYear()).substring(2, 4) + ";
1273 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1275 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1277 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1279 return "this.getHours() + ";
1281 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1283 return "String.leftPad(this.getHours(), 2, '0') + ";
1285 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1287 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1289 return "this.getGMTOffset() + ";
1291 return "this.getGMTColonOffset() + ";
1293 return "this.getTimezone() + ";
1295 return "(this.getTimezoneOffset() * -60) + ";
1297 return "'" + String.escape(character) + "' + ";
1302 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1303 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1304 * the date format that is not specified will default to the current date value for that part. Time parts can also
1305 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1306 * string or the parse operation will fail.
1309 //dt = Fri May 25 2007 (current date)
1310 var dt = new Date();
1312 //dt = Thu May 25 2006 (today's month/day in 2006)
1313 dt = Date.parseDate("2006", "Y");
1315 //dt = Sun Jan 15 2006 (all date parts specified)
1316 dt = Date.parseDate("2006-1-15", "Y-m-d");
1318 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1319 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1321 * @param {String} input The unparsed date as a string
1322 * @param {String} format The format the date is in
1323 * @return {Date} The parsed date
1326 Date.parseDate = function(input, format) {
1327 if (Date.parseFunctions[format] == null) {
1328 Date.createParser(format);
1330 var func = Date.parseFunctions[format];
1331 return Date[func](input);
1337 Date.createParser = function(format) {
1338 var funcName = "parse" + Date.parseFunctions.count++;
1339 var regexNum = Date.parseRegexes.length;
1340 var currentGroup = 1;
1341 Date.parseFunctions[format] = funcName;
1343 var code = "Date." + funcName + " = function(input){\n"
1344 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1345 + "var d = new Date();\n"
1346 + "y = d.getFullYear();\n"
1347 + "m = d.getMonth();\n"
1348 + "d = d.getDate();\n"
1349 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1350 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1351 + "if (results && results.length > 0) {";
1354 var special = false;
1356 for (var i = 0; i < format.length; ++i) {
1357 ch = format.charAt(i);
1358 if (!special && ch == "\\") {
1363 regex += String.escape(ch);
1366 var obj = Date.formatCodeToRegex(ch, currentGroup);
1367 currentGroup += obj.g;
1369 if (obj.g && obj.c) {
1375 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1376 + "{v = new Date(y, m, d, h, i, s);}\n"
1377 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1378 + "{v = new Date(y, m, d, h, i);}\n"
1379 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1380 + "{v = new Date(y, m, d, h);}\n"
1381 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1382 + "{v = new Date(y, m, d);}\n"
1383 + "else if (y >= 0 && m >= 0)\n"
1384 + "{v = new Date(y, m);}\n"
1385 + "else if (y >= 0)\n"
1386 + "{v = new Date(y);}\n"
1387 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1388 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1389 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1392 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1393 /** eval:var:zzzzzzzzzzzzz */
1398 Date.formatCodeToRegex = function(character, currentGroup) {
1399 switch (character) {
1403 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1406 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1407 s:"(\\d{1,2})"}; // day of month without leading zeroes
1410 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1411 s:"(\\d{2})"}; // day of month with leading zeroes
1415 s:"(?:" + Date.dayNames.join("|") + ")"};
1419 s:"(?:st|nd|rd|th)"};
1434 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1435 s:"(" + Date.monthNames.join("|") + ")"};
1438 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1439 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1442 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1443 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1446 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1447 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1458 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1462 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1463 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1467 c:"if (results[" + currentGroup + "] == 'am') {\n"
1468 + "if (h == 12) { h = 0; }\n"
1469 + "} else { if (h < 12) { h += 12; }}",
1473 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1474 + "if (h == 12) { h = 0; }\n"
1475 + "} else { if (h < 12) { h += 12; }}",
1480 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1481 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1485 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1486 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1489 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1493 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1498 "o = results[", currentGroup, "];\n",
1499 "var sn = o.substring(0,1);\n", // get + / - sign
1500 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1501 "var mn = o.substring(3,5) % 60;\n", // get minutes
1502 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1503 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1505 s:"([+\-]\\d{2,4})"};
1511 "o = results[", currentGroup, "];\n",
1512 "var sn = o.substring(0,1);\n",
1513 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1514 "var mn = o.substring(4,6) % 60;\n",
1515 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1516 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1522 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1525 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1526 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1527 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1531 s:String.escape(character)};
1536 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1537 * @return {String} The abbreviated timezone name (e.g. 'CST')
1539 Date.prototype.getTimezone = function() {
1540 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1544 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1545 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1547 Date.prototype.getGMTOffset = function() {
1548 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1549 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1550 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1554 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1555 * @return {String} 2-characters representing hours and 2-characters representing minutes
1556 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1558 Date.prototype.getGMTColonOffset = function() {
1559 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1560 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1562 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1566 * Get the numeric day number of the year, adjusted for leap year.
1567 * @return {Number} 0 through 364 (365 in leap years)
1569 Date.prototype.getDayOfYear = function() {
1571 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1572 for (var i = 0; i < this.getMonth(); ++i) {
1573 num += Date.daysInMonth[i];
1575 return num + this.getDate() - 1;
1579 * Get the string representation of the numeric week number of the year
1580 * (equivalent to the format specifier 'W').
1581 * @return {String} '00' through '52'
1583 Date.prototype.getWeekOfYear = function() {
1584 // Skip to Thursday of this week
1585 var now = this.getDayOfYear() + (4 - this.getDay());
1586 // Find the first Thursday of the year
1587 var jan1 = new Date(this.getFullYear(), 0, 1);
1588 var then = (7 - jan1.getDay() + 4);
1589 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1593 * Whether or not the current date is in a leap year.
1594 * @return {Boolean} True if the current date is in a leap year, else false
1596 Date.prototype.isLeapYear = function() {
1597 var year = this.getFullYear();
1598 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1602 * Get the first day of the current month, adjusted for leap year. The returned value
1603 * is the numeric day index within the week (0-6) which can be used in conjunction with
1604 * the {@link #monthNames} array to retrieve the textual day name.
1607 var dt = new Date('1/10/2007');
1608 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1610 * @return {Number} The day number (0-6)
1612 Date.prototype.getFirstDayOfMonth = function() {
1613 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1614 return (day < 0) ? (day + 7) : day;
1618 * Get the last day of the current month, adjusted for leap year. The returned value
1619 * is the numeric day index within the week (0-6) which can be used in conjunction with
1620 * the {@link #monthNames} array to retrieve the textual day name.
1623 var dt = new Date('1/10/2007');
1624 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1626 * @return {Number} The day number (0-6)
1628 Date.prototype.getLastDayOfMonth = function() {
1629 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1630 return (day < 0) ? (day + 7) : day;
1635 * Get the first date of this date's month
1638 Date.prototype.getFirstDateOfMonth = function() {
1639 return new Date(this.getFullYear(), this.getMonth(), 1);
1643 * Get the last date of this date's month
1646 Date.prototype.getLastDateOfMonth = function() {
1647 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1650 * Get the number of days in the current month, adjusted for leap year.
1651 * @return {Number} The number of days in the month
1653 Date.prototype.getDaysInMonth = function() {
1654 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1655 return Date.daysInMonth[this.getMonth()];
1659 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1660 * @return {String} 'st, 'nd', 'rd' or 'th'
1662 Date.prototype.getSuffix = function() {
1663 switch (this.getDate()) {
1680 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1683 * An array of textual month names.
1684 * Override these values for international dates, for example...
1685 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1704 * An array of textual day names.
1705 * Override these values for international dates, for example...
1706 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1722 Date.monthNumbers = {
1737 * Creates and returns a new Date instance with the exact same date value as the called instance.
1738 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1739 * variable will also be changed. When the intention is to create a new variable that will not
1740 * modify the original instance, you should create a clone.
1742 * Example of correctly cloning a date:
1745 var orig = new Date('10/1/2006');
1748 document.write(orig); //returns 'Thu Oct 05 2006'!
1751 var orig = new Date('10/1/2006');
1752 var copy = orig.clone();
1754 document.write(orig); //returns 'Thu Oct 01 2006'
1756 * @return {Date} The new Date instance
1758 Date.prototype.clone = function() {
1759 return new Date(this.getTime());
1763 * Clears any time information from this date
1764 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1765 @return {Date} this or the clone
1767 Date.prototype.clearTime = function(clone){
1769 return this.clone().clearTime();
1774 this.setMilliseconds(0);
1779 // safari setMonth is broken -- check that this is only donw once...
1780 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1781 Date.brokenSetMonth = Date.prototype.setMonth;
1782 Date.prototype.setMonth = function(num){
1784 var n = Math.ceil(-num);
1785 var back_year = Math.ceil(n/12);
1786 var month = (n % 12) ? 12 - n % 12 : 0 ;
1787 this.setFullYear(this.getFullYear() - back_year);
1788 return Date.brokenSetMonth.call(this, month);
1790 return Date.brokenSetMonth.apply(this, arguments);
1795 /** Date interval constant
1799 /** Date interval constant
1803 /** Date interval constant
1807 /** Date interval constant
1811 /** Date interval constant
1815 /** Date interval constant
1819 /** Date interval constant
1825 * Provides a convenient method of performing basic date arithmetic. This method
1826 * does not modify the Date instance being called - it creates and returns
1827 * a new Date instance containing the resulting date value.
1832 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1833 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1835 //Negative values will subtract correctly:
1836 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1837 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1839 //You can even chain several calls together in one line!
1840 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1841 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1844 * @param {String} interval A valid date interval enum value
1845 * @param {Number} value The amount to add to the current date
1846 * @return {Date} The new Date instance
1848 Date.prototype.add = function(interval, value){
1849 var d = this.clone();
1850 if (!interval || value === 0) { return d; }
1851 switch(interval.toLowerCase()){
1853 d.setMilliseconds(this.getMilliseconds() + value);
1856 d.setSeconds(this.getSeconds() + value);
1859 d.setMinutes(this.getMinutes() + value);
1862 d.setHours(this.getHours() + value);
1865 d.setDate(this.getDate() + value);
1868 var day = this.getDate();
1870 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1873 d.setMonth(this.getMonth() + value);
1876 d.setFullYear(this.getFullYear() + value);
1882 * @class Roo.lib.Dom
1886 * Dom utils (from YIU afaik)
1892 * Get the view width
1893 * @param {Boolean} full True will get the full document, otherwise it's the view width
1894 * @return {Number} The width
1897 getViewWidth : function(full) {
1898 return full ? this.getDocumentWidth() : this.getViewportWidth();
1901 * Get the view height
1902 * @param {Boolean} full True will get the full document, otherwise it's the view height
1903 * @return {Number} The height
1905 getViewHeight : function(full) {
1906 return full ? this.getDocumentHeight() : this.getViewportHeight();
1909 * Get the Full Document height
1910 * @return {Number} The height
1912 getDocumentHeight: function() {
1913 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1914 return Math.max(scrollHeight, this.getViewportHeight());
1917 * Get the Full Document width
1918 * @return {Number} The width
1920 getDocumentWidth: function() {
1921 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1922 return Math.max(scrollWidth, this.getViewportWidth());
1925 * Get the Window Viewport height
1926 * @return {Number} The height
1928 getViewportHeight: function() {
1929 var height = self.innerHeight;
1930 var mode = document.compatMode;
1932 if ((mode || Roo.isIE) && !Roo.isOpera) {
1933 height = (mode == "CSS1Compat") ?
1934 document.documentElement.clientHeight :
1935 document.body.clientHeight;
1941 * Get the Window Viewport width
1942 * @return {Number} The width
1944 getViewportWidth: function() {
1945 var width = self.innerWidth;
1946 var mode = document.compatMode;
1948 if (mode || Roo.isIE) {
1949 width = (mode == "CSS1Compat") ?
1950 document.documentElement.clientWidth :
1951 document.body.clientWidth;
1956 isAncestor : function(p, c) {
1963 if (p.contains && !Roo.isSafari) {
1964 return p.contains(c);
1965 } else if (p.compareDocumentPosition) {
1966 return !!(p.compareDocumentPosition(c) & 16);
1968 var parent = c.parentNode;
1973 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1976 parent = parent.parentNode;
1982 getRegion : function(el) {
1983 return Roo.lib.Region.getRegion(el);
1986 getY : function(el) {
1987 return this.getXY(el)[1];
1990 getX : function(el) {
1991 return this.getXY(el)[0];
1994 getXY : function(el) {
1995 var p, pe, b, scroll, bd = document.body;
1996 el = Roo.getDom(el);
1997 var fly = Roo.lib.AnimBase.fly;
1998 if (el.getBoundingClientRect) {
1999 b = el.getBoundingClientRect();
2000 scroll = fly(document).getScroll();
2001 return [b.left + scroll.left, b.top + scroll.top];
2007 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2014 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2021 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2022 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2029 if (p != el && pe.getStyle('overflow') != 'visible') {
2037 if (Roo.isSafari && hasAbsolute) {
2042 if (Roo.isGecko && !hasAbsolute) {
2044 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2045 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2049 while (p && p != bd) {
2050 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2062 setXY : function(el, xy) {
2063 el = Roo.fly(el, '_setXY');
2065 var pts = el.translatePoints(xy);
2066 if (xy[0] !== false) {
2067 el.dom.style.left = pts.left + "px";
2069 if (xy[1] !== false) {
2070 el.dom.style.top = pts.top + "px";
2074 setX : function(el, x) {
2075 this.setXY(el, [x, false]);
2078 setY : function(el, y) {
2079 this.setXY(el, [false, y]);
2083 * Portions of this file are based on pieces of Yahoo User Interface Library
2084 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2085 * YUI licensed under the BSD License:
2086 * http://developer.yahoo.net/yui/license.txt
2087 * <script type="text/javascript">
2091 Roo.lib.Event = function() {
2092 var loadComplete = false;
2094 var unloadListeners = [];
2096 var onAvailStack = [];
2098 var lastError = null;
2111 startInterval: function() {
2112 if (!this._interval) {
2114 var callback = function() {
2115 self._tryPreloadAttach();
2117 this._interval = setInterval(callback, this.POLL_INTERVAL);
2122 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2123 onAvailStack.push({ id: p_id,
2126 override: p_override,
2127 checkReady: false });
2129 retryCount = this.POLL_RETRYS;
2130 this.startInterval();
2134 addListener: function(el, eventName, fn) {
2135 el = Roo.getDom(el);
2140 if ("unload" == eventName) {
2141 unloadListeners[unloadListeners.length] =
2142 [el, eventName, fn];
2146 var wrappedFn = function(e) {
2147 return fn(Roo.lib.Event.getEvent(e));
2150 var li = [el, eventName, fn, wrappedFn];
2152 var index = listeners.length;
2153 listeners[index] = li;
2155 this.doAdd(el, eventName, wrappedFn, false);
2161 removeListener: function(el, eventName, fn) {
2164 el = Roo.getDom(el);
2167 return this.purgeElement(el, false, eventName);
2171 if ("unload" == eventName) {
2173 for (i = 0,len = unloadListeners.length; i < len; i++) {
2174 var li = unloadListeners[i];
2177 li[1] == eventName &&
2179 unloadListeners.splice(i, 1);
2187 var cacheItem = null;
2190 var index = arguments[3];
2192 if ("undefined" == typeof index) {
2193 index = this._getCacheIndex(el, eventName, fn);
2197 cacheItem = listeners[index];
2200 if (!el || !cacheItem) {
2204 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2206 delete listeners[index][this.WFN];
2207 delete listeners[index][this.FN];
2208 listeners.splice(index, 1);
2215 getTarget: function(ev, resolveTextNode) {
2216 ev = ev.browserEvent || ev;
2217 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2218 var t = ev.target || ev.srcElement;
2219 return this.resolveTextNode(t);
2223 resolveTextNode: function(node) {
2224 if (Roo.isSafari && node && 3 == node.nodeType) {
2225 return node.parentNode;
2232 getPageX: function(ev) {
2233 ev = ev.browserEvent || ev;
2234 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2236 if (!x && 0 !== x) {
2237 x = ev.clientX || 0;
2240 x += this.getScroll()[1];
2248 getPageY: function(ev) {
2249 ev = ev.browserEvent || ev;
2250 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2252 if (!y && 0 !== y) {
2253 y = ev.clientY || 0;
2256 y += this.getScroll()[0];
2265 getXY: function(ev) {
2266 ev = ev.browserEvent || ev;
2267 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2268 return [this.getPageX(ev), this.getPageY(ev)];
2272 getRelatedTarget: function(ev) {
2273 ev = ev.browserEvent || ev;
2274 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2275 var t = ev.relatedTarget;
2277 if (ev.type == "mouseout") {
2279 } else if (ev.type == "mouseover") {
2284 return this.resolveTextNode(t);
2288 getTime: function(ev) {
2289 ev = ev.browserEvent || ev;
2290 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2292 var t = new Date().getTime();
2296 this.lastError = ex;
2305 stopEvent: function(ev) {
2306 this.stopPropagation(ev);
2307 this.preventDefault(ev);
2311 stopPropagation: function(ev) {
2312 ev = ev.browserEvent || ev;
2313 if (ev.stopPropagation) {
2314 ev.stopPropagation();
2316 ev.cancelBubble = true;
2321 preventDefault: function(ev) {
2322 ev = ev.browserEvent || ev;
2323 if(ev.preventDefault) {
2324 ev.preventDefault();
2326 ev.returnValue = false;
2331 getEvent: function(e) {
2332 var ev = e || window.event;
2334 var c = this.getEvent.caller;
2336 ev = c.arguments[0];
2337 if (ev && Event == ev.constructor) {
2347 getCharCode: function(ev) {
2348 ev = ev.browserEvent || ev;
2349 return ev.charCode || ev.keyCode || 0;
2353 _getCacheIndex: function(el, eventName, fn) {
2354 for (var i = 0,len = listeners.length; i < len; ++i) {
2355 var li = listeners[i];
2357 li[this.FN] == fn &&
2358 li[this.EL] == el &&
2359 li[this.TYPE] == eventName) {
2371 getEl: function(id) {
2372 return document.getElementById(id);
2376 clearCache: function() {
2380 _load: function(e) {
2381 loadComplete = true;
2382 var EU = Roo.lib.Event;
2386 EU.doRemove(window, "load", EU._load);
2391 _tryPreloadAttach: function() {
2400 var tryAgain = !loadComplete;
2402 tryAgain = (retryCount > 0);
2407 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2408 var item = onAvailStack[i];
2410 var el = this.getEl(item.id);
2413 if (!item.checkReady ||
2416 (document && document.body)) {
2419 if (item.override) {
2420 if (item.override === true) {
2423 scope = item.override;
2426 item.fn.call(scope, item.obj);
2427 onAvailStack[i] = null;
2430 notAvail.push(item);
2435 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2439 this.startInterval();
2441 clearInterval(this._interval);
2442 this._interval = null;
2445 this.locked = false;
2452 purgeElement: function(el, recurse, eventName) {
2453 var elListeners = this.getListeners(el, eventName);
2455 for (var i = 0,len = elListeners.length; i < len; ++i) {
2456 var l = elListeners[i];
2457 this.removeListener(el, l.type, l.fn);
2461 if (recurse && el && el.childNodes) {
2462 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2463 this.purgeElement(el.childNodes[i], recurse, eventName);
2469 getListeners: function(el, eventName) {
2470 var results = [], searchLists;
2472 searchLists = [listeners, unloadListeners];
2473 } else if (eventName == "unload") {
2474 searchLists = [unloadListeners];
2476 searchLists = [listeners];
2479 for (var j = 0; j < searchLists.length; ++j) {
2480 var searchList = searchLists[j];
2481 if (searchList && searchList.length > 0) {
2482 for (var i = 0,len = searchList.length; i < len; ++i) {
2483 var l = searchList[i];
2484 if (l && l[this.EL] === el &&
2485 (!eventName || eventName === l[this.TYPE])) {
2490 adjust: l[this.ADJ_SCOPE],
2498 return (results.length) ? results : null;
2502 _unload: function(e) {
2504 var EU = Roo.lib.Event, i, j, l, len, index;
2506 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2507 l = unloadListeners[i];
2510 if (l[EU.ADJ_SCOPE]) {
2511 if (l[EU.ADJ_SCOPE] === true) {
2514 scope = l[EU.ADJ_SCOPE];
2517 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2518 unloadListeners[i] = null;
2524 unloadListeners = null;
2526 if (listeners && listeners.length > 0) {
2527 j = listeners.length;
2530 l = listeners[index];
2532 EU.removeListener(l[EU.EL], l[EU.TYPE],
2542 EU.doRemove(window, "unload", EU._unload);
2547 getScroll: function() {
2548 var dd = document.documentElement, db = document.body;
2549 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2550 return [dd.scrollTop, dd.scrollLeft];
2552 return [db.scrollTop, db.scrollLeft];
2559 doAdd: function () {
2560 if (window.addEventListener) {
2561 return function(el, eventName, fn, capture) {
2562 el.addEventListener(eventName, fn, (capture));
2564 } else if (window.attachEvent) {
2565 return function(el, eventName, fn, capture) {
2566 el.attachEvent("on" + eventName, fn);
2575 doRemove: function() {
2576 if (window.removeEventListener) {
2577 return function (el, eventName, fn, capture) {
2578 el.removeEventListener(eventName, fn, (capture));
2580 } else if (window.detachEvent) {
2581 return function (el, eventName, fn) {
2582 el.detachEvent("on" + eventName, fn);
2594 var E = Roo.lib.Event;
2595 E.on = E.addListener;
2596 E.un = E.removeListener;
2598 if (document && document.body) {
2601 E.doAdd(window, "load", E._load);
2603 E.doAdd(window, "unload", E._unload);
2604 E._tryPreloadAttach();
2608 * Portions of this file are based on pieces of Yahoo User Interface Library
2609 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2610 * YUI licensed under the BSD License:
2611 * http://developer.yahoo.net/yui/license.txt
2612 * <script type="text/javascript">
2618 * @class Roo.lib.Ajax
2625 request : function(method, uri, cb, data, options) {
2627 var hs = options.headers;
2630 if(hs.hasOwnProperty(h)){
2631 this.initHeader(h, hs[h], false);
2635 if(options.xmlData){
2636 this.initHeader('Content-Type', 'text/xml', false);
2638 data = options.xmlData;
2642 return this.asyncRequest(method, uri, cb, data);
2645 serializeForm : function(form) {
2646 if(typeof form == 'string') {
2647 form = (document.getElementById(form) || document.forms[form]);
2650 var el, name, val, disabled, data = '', hasSubmit = false;
2651 for (var i = 0; i < form.elements.length; i++) {
2652 el = form.elements[i];
2653 disabled = form.elements[i].disabled;
2654 name = form.elements[i].name;
2655 val = form.elements[i].value;
2657 if (!disabled && name){
2661 case 'select-multiple':
2662 for (var j = 0; j < el.options.length; j++) {
2663 if (el.options[j].selected) {
2665 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2668 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2676 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2689 if(hasSubmit == false) {
2690 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2695 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2700 data = data.substr(0, data.length - 1);
2708 useDefaultHeader:true,
2710 defaultPostHeader:'application/x-www-form-urlencoded',
2712 useDefaultXhrHeader:true,
2714 defaultXhrHeader:'XMLHttpRequest',
2716 hasDefaultHeaders:true,
2728 setProgId:function(id)
2730 this.activeX.unshift(id);
2733 setDefaultPostHeader:function(b)
2735 this.useDefaultHeader = b;
2738 setDefaultXhrHeader:function(b)
2740 this.useDefaultXhrHeader = b;
2743 setPollingInterval:function(i)
2745 if (typeof i == 'number' && isFinite(i)) {
2746 this.pollInterval = i;
2750 createXhrObject:function(transactionId)
2756 http = new XMLHttpRequest();
2758 obj = { conn:http, tId:transactionId };
2762 for (var i = 0; i < this.activeX.length; ++i) {
2766 http = new ActiveXObject(this.activeX[i]);
2768 obj = { conn:http, tId:transactionId };
2781 getConnectionObject:function()
2784 var tId = this.transactionId;
2788 o = this.createXhrObject(tId);
2790 this.transactionId++;
2801 asyncRequest:function(method, uri, callback, postData)
2803 var o = this.getConnectionObject();
2809 o.conn.open(method, uri, true);
2811 if (this.useDefaultXhrHeader) {
2812 if (!this.defaultHeaders['X-Requested-With']) {
2813 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2817 if(postData && this.useDefaultHeader){
2818 this.initHeader('Content-Type', this.defaultPostHeader);
2821 if (this.hasDefaultHeaders || this.hasHeaders) {
2825 this.handleReadyState(o, callback);
2826 o.conn.send(postData || null);
2832 handleReadyState:function(o, callback)
2836 if (callback && callback.timeout) {
2838 this.timeout[o.tId] = window.setTimeout(function() {
2839 oConn.abort(o, callback, true);
2840 }, callback.timeout);
2843 this.poll[o.tId] = window.setInterval(
2845 if (o.conn && o.conn.readyState == 4) {
2846 window.clearInterval(oConn.poll[o.tId]);
2847 delete oConn.poll[o.tId];
2849 if(callback && callback.timeout) {
2850 window.clearTimeout(oConn.timeout[o.tId]);
2851 delete oConn.timeout[o.tId];
2854 oConn.handleTransactionResponse(o, callback);
2857 , this.pollInterval);
2860 handleTransactionResponse:function(o, callback, isAbort)
2864 this.releaseObject(o);
2868 var httpStatus, responseObject;
2872 if (o.conn.status !== undefined && o.conn.status != 0) {
2873 httpStatus = o.conn.status;
2885 if (httpStatus >= 200 && httpStatus < 300) {
2886 responseObject = this.createResponseObject(o, callback.argument);
2887 if (callback.success) {
2888 if (!callback.scope) {
2889 callback.success(responseObject);
2894 callback.success.apply(callback.scope, [responseObject]);
2899 switch (httpStatus) {
2907 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2908 if (callback.failure) {
2909 if (!callback.scope) {
2910 callback.failure(responseObject);
2913 callback.failure.apply(callback.scope, [responseObject]);
2918 responseObject = this.createResponseObject(o, callback.argument);
2919 if (callback.failure) {
2920 if (!callback.scope) {
2921 callback.failure(responseObject);
2924 callback.failure.apply(callback.scope, [responseObject]);
2930 this.releaseObject(o);
2931 responseObject = null;
2934 createResponseObject:function(o, callbackArg)
2941 var headerStr = o.conn.getAllResponseHeaders();
2942 var header = headerStr.split('\n');
2943 for (var i = 0; i < header.length; i++) {
2944 var delimitPos = header[i].indexOf(':');
2945 if (delimitPos != -1) {
2946 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2954 obj.status = o.conn.status;
2955 obj.statusText = o.conn.statusText;
2956 obj.getResponseHeader = headerObj;
2957 obj.getAllResponseHeaders = headerStr;
2958 obj.responseText = o.conn.responseText;
2959 obj.responseXML = o.conn.responseXML;
2961 if (typeof callbackArg !== undefined) {
2962 obj.argument = callbackArg;
2968 createExceptionObject:function(tId, callbackArg, isAbort)
2971 var COMM_ERROR = 'communication failure';
2972 var ABORT_CODE = -1;
2973 var ABORT_ERROR = 'transaction aborted';
2979 obj.status = ABORT_CODE;
2980 obj.statusText = ABORT_ERROR;
2983 obj.status = COMM_CODE;
2984 obj.statusText = COMM_ERROR;
2988 obj.argument = callbackArg;
2994 initHeader:function(label, value, isDefault)
2996 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2998 if (headerObj[label] === undefined) {
2999 headerObj[label] = value;
3004 headerObj[label] = value + "," + headerObj[label];
3008 this.hasDefaultHeaders = true;
3011 this.hasHeaders = true;
3016 setHeader:function(o)
3018 if (this.hasDefaultHeaders) {
3019 for (var prop in this.defaultHeaders) {
3020 if (this.defaultHeaders.hasOwnProperty(prop)) {
3021 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3026 if (this.hasHeaders) {
3027 for (var prop in this.headers) {
3028 if (this.headers.hasOwnProperty(prop)) {
3029 o.conn.setRequestHeader(prop, this.headers[prop]);
3033 this.hasHeaders = false;
3037 resetDefaultHeaders:function() {
3038 delete this.defaultHeaders;
3039 this.defaultHeaders = {};
3040 this.hasDefaultHeaders = false;
3043 abort:function(o, callback, isTimeout)
3045 if(this.isCallInProgress(o)) {
3047 window.clearInterval(this.poll[o.tId]);
3048 delete this.poll[o.tId];
3050 delete this.timeout[o.tId];
3053 this.handleTransactionResponse(o, callback, true);
3063 isCallInProgress:function(o)
3066 return o.conn.readyState != 4 && o.conn.readyState != 0;
3075 releaseObject:function(o)
3084 'MSXML2.XMLHTTP.3.0',
3092 * Portions of this file are based on pieces of Yahoo User Interface Library
3093 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3094 * YUI licensed under the BSD License:
3095 * http://developer.yahoo.net/yui/license.txt
3096 * <script type="text/javascript">
3100 Roo.lib.Region = function(t, r, b, l) {
3110 Roo.lib.Region.prototype = {
3111 contains : function(region) {
3112 return ( region.left >= this.left &&
3113 region.right <= this.right &&
3114 region.top >= this.top &&
3115 region.bottom <= this.bottom );
3119 getArea : function() {
3120 return ( (this.bottom - this.top) * (this.right - this.left) );
3123 intersect : function(region) {
3124 var t = Math.max(this.top, region.top);
3125 var r = Math.min(this.right, region.right);
3126 var b = Math.min(this.bottom, region.bottom);
3127 var l = Math.max(this.left, region.left);
3129 if (b >= t && r >= l) {
3130 return new Roo.lib.Region(t, r, b, l);
3135 union : function(region) {
3136 var t = Math.min(this.top, region.top);
3137 var r = Math.max(this.right, region.right);
3138 var b = Math.max(this.bottom, region.bottom);
3139 var l = Math.min(this.left, region.left);
3141 return new Roo.lib.Region(t, r, b, l);
3144 adjust : function(t, l, b, r) {
3153 Roo.lib.Region.getRegion = function(el) {
3154 var p = Roo.lib.Dom.getXY(el);
3157 var r = p[0] + el.offsetWidth;
3158 var b = p[1] + el.offsetHeight;
3161 return new Roo.lib.Region(t, r, b, l);
3164 * Portions of this file are based on pieces of Yahoo User Interface Library
3165 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3166 * YUI licensed under the BSD License:
3167 * http://developer.yahoo.net/yui/license.txt
3168 * <script type="text/javascript">
3171 //@@dep Roo.lib.Region
3174 Roo.lib.Point = function(x, y) {
3175 if (x instanceof Array) {
3179 this.x = this.right = this.left = this[0] = x;
3180 this.y = this.top = this.bottom = this[1] = y;
3183 Roo.lib.Point.prototype = new Roo.lib.Region();
3185 * Portions of this file are based on pieces of Yahoo User Interface Library
3186 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3187 * YUI licensed under the BSD License:
3188 * http://developer.yahoo.net/yui/license.txt
3189 * <script type="text/javascript">
3196 scroll : function(el, args, duration, easing, cb, scope) {
3197 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3200 motion : function(el, args, duration, easing, cb, scope) {
3201 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3204 color : function(el, args, duration, easing, cb, scope) {
3205 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3208 run : function(el, args, duration, easing, cb, scope, type) {
3209 type = type || Roo.lib.AnimBase;
3210 if (typeof easing == "string") {
3211 easing = Roo.lib.Easing[easing];
3213 var anim = new type(el, args, duration, easing);
3214 anim.animateX(function() {
3215 Roo.callback(cb, scope);
3221 * Portions of this file are based on pieces of Yahoo User Interface Library
3222 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3223 * YUI licensed under the BSD License:
3224 * http://developer.yahoo.net/yui/license.txt
3225 * <script type="text/javascript">
3233 if (!libFlyweight) {
3234 libFlyweight = new Roo.Element.Flyweight();
3236 libFlyweight.dom = el;
3237 return libFlyweight;
3240 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3244 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3246 this.init(el, attributes, duration, method);
3250 Roo.lib.AnimBase.fly = fly;
3254 Roo.lib.AnimBase.prototype = {
3256 toString: function() {
3257 var el = this.getEl();
3258 var id = el.id || el.tagName;
3259 return ("Anim " + id);
3263 noNegatives: /width|height|opacity|padding/i,
3264 offsetAttribute: /^((width|height)|(top|left))$/,
3265 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3266 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3270 doMethod: function(attr, start, end) {
3271 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3275 setAttribute: function(attr, val, unit) {
3276 if (this.patterns.noNegatives.test(attr)) {
3277 val = (val > 0) ? val : 0;
3280 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3284 getAttribute: function(attr) {
3285 var el = this.getEl();
3286 var val = fly(el).getStyle(attr);
3288 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3289 return parseFloat(val);
3292 var a = this.patterns.offsetAttribute.exec(attr) || [];
3293 var pos = !!( a[3] );
3294 var box = !!( a[2] );
3297 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3298 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3307 getDefaultUnit: function(attr) {
3308 if (this.patterns.defaultUnit.test(attr)) {
3315 animateX : function(callback, scope) {
3316 var f = function() {
3317 this.onComplete.removeListener(f);
3318 if (typeof callback == "function") {
3319 callback.call(scope || this, this);
3322 this.onComplete.addListener(f, this);
3327 setRuntimeAttribute: function(attr) {
3330 var attributes = this.attributes;
3332 this.runtimeAttributes[attr] = {};
3334 var isset = function(prop) {
3335 return (typeof prop !== 'undefined');
3338 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3342 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3345 if (isset(attributes[attr]['to'])) {
3346 end = attributes[attr]['to'];
3347 } else if (isset(attributes[attr]['by'])) {
3348 if (start.constructor == Array) {
3350 for (var i = 0, len = start.length; i < len; ++i) {
3351 end[i] = start[i] + attributes[attr]['by'][i];
3354 end = start + attributes[attr]['by'];
3358 this.runtimeAttributes[attr].start = start;
3359 this.runtimeAttributes[attr].end = end;
3362 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3366 init: function(el, attributes, duration, method) {
3368 var isAnimated = false;
3371 var startTime = null;
3374 var actualFrames = 0;
3377 el = Roo.getDom(el);
3380 this.attributes = attributes || {};
3383 this.duration = duration || 1;
3386 this.method = method || Roo.lib.Easing.easeNone;
3389 this.useSeconds = true;
3392 this.currentFrame = 0;
3395 this.totalFrames = Roo.lib.AnimMgr.fps;
3398 this.getEl = function() {
3403 this.isAnimated = function() {
3408 this.getStartTime = function() {
3412 this.runtimeAttributes = {};
3415 this.animate = function() {
3416 if (this.isAnimated()) {
3420 this.currentFrame = 0;
3422 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3424 Roo.lib.AnimMgr.registerElement(this);
3428 this.stop = function(finish) {
3430 this.currentFrame = this.totalFrames;
3431 this._onTween.fire();
3433 Roo.lib.AnimMgr.stop(this);
3436 var onStart = function() {
3437 this.onStart.fire();
3439 this.runtimeAttributes = {};
3440 for (var attr in this.attributes) {
3441 this.setRuntimeAttribute(attr);
3446 startTime = new Date();
3450 var onTween = function() {
3452 duration: new Date() - this.getStartTime(),
3453 currentFrame: this.currentFrame
3456 data.toString = function() {
3458 'duration: ' + data.duration +
3459 ', currentFrame: ' + data.currentFrame
3463 this.onTween.fire(data);
3465 var runtimeAttributes = this.runtimeAttributes;
3467 for (var attr in runtimeAttributes) {
3468 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3474 var onComplete = function() {
3475 var actual_duration = (new Date() - startTime) / 1000 ;
3478 duration: actual_duration,
3479 frames: actualFrames,
3480 fps: actualFrames / actual_duration
3483 data.toString = function() {
3485 'duration: ' + data.duration +
3486 ', frames: ' + data.frames +
3487 ', fps: ' + data.fps
3493 this.onComplete.fire(data);
3497 this._onStart = new Roo.util.Event(this);
3498 this.onStart = new Roo.util.Event(this);
3499 this.onTween = new Roo.util.Event(this);
3500 this._onTween = new Roo.util.Event(this);
3501 this.onComplete = new Roo.util.Event(this);
3502 this._onComplete = new Roo.util.Event(this);
3503 this._onStart.addListener(onStart);
3504 this._onTween.addListener(onTween);
3505 this._onComplete.addListener(onComplete);
3510 * Portions of this file are based on pieces of Yahoo User Interface Library
3511 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3512 * YUI licensed under the BSD License:
3513 * http://developer.yahoo.net/yui/license.txt
3514 * <script type="text/javascript">
3518 Roo.lib.AnimMgr = new function() {
3535 this.registerElement = function(tween) {
3536 queue[queue.length] = tween;
3538 tween._onStart.fire();
3543 this.unRegister = function(tween, index) {
3544 tween._onComplete.fire();
3545 index = index || getIndex(tween);
3547 queue.splice(index, 1);
3551 if (tweenCount <= 0) {
3557 this.start = function() {
3558 if (thread === null) {
3559 thread = setInterval(this.run, this.delay);
3564 this.stop = function(tween) {
3566 clearInterval(thread);
3568 for (var i = 0, len = queue.length; i < len; ++i) {
3569 if (queue[0].isAnimated()) {
3570 this.unRegister(queue[0], 0);
3579 this.unRegister(tween);
3584 this.run = function() {
3585 for (var i = 0, len = queue.length; i < len; ++i) {
3586 var tween = queue[i];
3587 if (!tween || !tween.isAnimated()) {
3591 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3593 tween.currentFrame += 1;
3595 if (tween.useSeconds) {
3596 correctFrame(tween);
3598 tween._onTween.fire();
3601 Roo.lib.AnimMgr.stop(tween, i);
3606 var getIndex = function(anim) {
3607 for (var i = 0, len = queue.length; i < len; ++i) {
3608 if (queue[i] == anim) {
3616 var correctFrame = function(tween) {
3617 var frames = tween.totalFrames;
3618 var frame = tween.currentFrame;
3619 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3620 var elapsed = (new Date() - tween.getStartTime());
3623 if (elapsed < tween.duration * 1000) {
3624 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3626 tweak = frames - (frame + 1);
3628 if (tweak > 0 && isFinite(tweak)) {
3629 if (tween.currentFrame + tweak >= frames) {
3630 tweak = frames - (frame + 1);
3633 tween.currentFrame += tweak;
3639 * Portions of this file are based on pieces of Yahoo User Interface Library
3640 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3641 * YUI licensed under the BSD License:
3642 * http://developer.yahoo.net/yui/license.txt
3643 * <script type="text/javascript">
3646 Roo.lib.Bezier = new function() {
3648 this.getPosition = function(points, t) {
3649 var n = points.length;
3652 for (var i = 0; i < n; ++i) {
3653 tmp[i] = [points[i][0], points[i][1]];
3656 for (var j = 1; j < n; ++j) {
3657 for (i = 0; i < n - j; ++i) {
3658 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3659 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3663 return [ tmp[0][0], tmp[0][1] ];
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">
3676 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3677 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3680 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3682 var fly = Roo.lib.AnimBase.fly;
3684 var superclass = Y.ColorAnim.superclass;
3685 var proto = Y.ColorAnim.prototype;
3687 proto.toString = function() {
3688 var el = this.getEl();
3689 var id = el.id || el.tagName;
3690 return ("ColorAnim " + id);
3693 proto.patterns.color = /color$/i;
3694 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3695 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3696 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3697 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3700 proto.parseColor = function(s) {
3701 if (s.length == 3) {
3705 var c = this.patterns.hex.exec(s);
3706 if (c && c.length == 4) {
3707 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3710 c = this.patterns.rgb.exec(s);
3711 if (c && c.length == 4) {
3712 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3715 c = this.patterns.hex3.exec(s);
3716 if (c && c.length == 4) {
3717 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3722 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3723 proto.getAttribute = function(attr) {
3724 var el = this.getEl();
3725 if (this.patterns.color.test(attr)) {
3726 var val = fly(el).getStyle(attr);
3728 if (this.patterns.transparent.test(val)) {
3729 var parent = el.parentNode;
3730 val = fly(parent).getStyle(attr);
3732 while (parent && this.patterns.transparent.test(val)) {
3733 parent = parent.parentNode;
3734 val = fly(parent).getStyle(attr);
3735 if (parent.tagName.toUpperCase() == 'HTML') {
3741 val = superclass.getAttribute.call(this, attr);
3746 proto.getAttribute = function(attr) {
3747 var el = this.getEl();
3748 if (this.patterns.color.test(attr)) {
3749 var val = fly(el).getStyle(attr);
3751 if (this.patterns.transparent.test(val)) {
3752 var parent = el.parentNode;
3753 val = fly(parent).getStyle(attr);
3755 while (parent && this.patterns.transparent.test(val)) {
3756 parent = parent.parentNode;
3757 val = fly(parent).getStyle(attr);
3758 if (parent.tagName.toUpperCase() == 'HTML') {
3764 val = superclass.getAttribute.call(this, attr);
3770 proto.doMethod = function(attr, start, end) {
3773 if (this.patterns.color.test(attr)) {
3775 for (var i = 0, len = start.length; i < len; ++i) {
3776 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3779 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3782 val = superclass.doMethod.call(this, attr, start, end);
3788 proto.setRuntimeAttribute = function(attr) {
3789 superclass.setRuntimeAttribute.call(this, attr);
3791 if (this.patterns.color.test(attr)) {
3792 var attributes = this.attributes;
3793 var start = this.parseColor(this.runtimeAttributes[attr].start);
3794 var end = this.parseColor(this.runtimeAttributes[attr].end);
3796 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3797 end = this.parseColor(attributes[attr].by);
3799 for (var i = 0, len = start.length; i < len; ++i) {
3800 end[i] = start[i] + end[i];
3804 this.runtimeAttributes[attr].start = start;
3805 this.runtimeAttributes[attr].end = end;
3811 * Portions of this file are based on pieces of Yahoo User Interface Library
3812 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3813 * YUI licensed under the BSD License:
3814 * http://developer.yahoo.net/yui/license.txt
3815 * <script type="text/javascript">
3821 easeNone: function (t, b, c, d) {
3822 return c * t / d + b;
3826 easeIn: function (t, b, c, d) {
3827 return c * (t /= d) * t + b;
3831 easeOut: function (t, b, c, d) {
3832 return -c * (t /= d) * (t - 2) + b;
3836 easeBoth: function (t, b, c, d) {
3837 if ((t /= d / 2) < 1) {
3838 return c / 2 * t * t + b;
3841 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3845 easeInStrong: function (t, b, c, d) {
3846 return c * (t /= d) * t * t * t + b;
3850 easeOutStrong: function (t, b, c, d) {
3851 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3855 easeBothStrong: function (t, b, c, d) {
3856 if ((t /= d / 2) < 1) {
3857 return c / 2 * t * t * t * t + b;
3860 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3865 elasticIn: function (t, b, c, d, a, p) {
3869 if ((t /= d) == 1) {
3876 if (!a || a < Math.abs(c)) {
3881 var s = p / (2 * Math.PI) * Math.asin(c / a);
3884 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3888 elasticOut: function (t, b, c, d, a, p) {
3892 if ((t /= d) == 1) {
3899 if (!a || a < Math.abs(c)) {
3904 var s = p / (2 * Math.PI) * Math.asin(c / a);
3907 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3911 elasticBoth: function (t, b, c, d, a, p) {
3916 if ((t /= d / 2) == 2) {
3924 if (!a || a < Math.abs(c)) {
3929 var s = p / (2 * Math.PI) * Math.asin(c / a);
3933 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3934 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3936 return a * Math.pow(2, -10 * (t -= 1)) *
3937 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3942 backIn: function (t, b, c, d, s) {
3943 if (typeof s == 'undefined') {
3946 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3950 backOut: function (t, b, c, d, s) {
3951 if (typeof s == 'undefined') {
3954 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3958 backBoth: function (t, b, c, d, s) {
3959 if (typeof s == 'undefined') {
3963 if ((t /= d / 2 ) < 1) {
3964 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3966 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3970 bounceIn: function (t, b, c, d) {
3971 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3975 bounceOut: function (t, b, c, d) {
3976 if ((t /= d) < (1 / 2.75)) {
3977 return c * (7.5625 * t * t) + b;
3978 } else if (t < (2 / 2.75)) {
3979 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3980 } else if (t < (2.5 / 2.75)) {
3981 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3983 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3987 bounceBoth: function (t, b, c, d) {
3989 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3991 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3994 * Portions of this file are based on pieces of Yahoo User Interface Library
3995 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3996 * YUI licensed under the BSD License:
3997 * http://developer.yahoo.net/yui/license.txt
3998 * <script type="text/javascript">
4002 Roo.lib.Motion = function(el, attributes, duration, method) {
4004 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4008 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4012 var superclass = Y.Motion.superclass;
4013 var proto = Y.Motion.prototype;
4015 proto.toString = function() {
4016 var el = this.getEl();
4017 var id = el.id || el.tagName;
4018 return ("Motion " + id);
4021 proto.patterns.points = /^points$/i;
4023 proto.setAttribute = function(attr, val, unit) {
4024 if (this.patterns.points.test(attr)) {
4025 unit = unit || 'px';
4026 superclass.setAttribute.call(this, 'left', val[0], unit);
4027 superclass.setAttribute.call(this, 'top', val[1], unit);
4029 superclass.setAttribute.call(this, attr, val, unit);
4033 proto.getAttribute = function(attr) {
4034 if (this.patterns.points.test(attr)) {
4036 superclass.getAttribute.call(this, 'left'),
4037 superclass.getAttribute.call(this, 'top')
4040 val = superclass.getAttribute.call(this, attr);
4046 proto.doMethod = function(attr, start, end) {
4049 if (this.patterns.points.test(attr)) {
4050 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4051 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4053 val = superclass.doMethod.call(this, attr, start, end);
4058 proto.setRuntimeAttribute = function(attr) {
4059 if (this.patterns.points.test(attr)) {
4060 var el = this.getEl();
4061 var attributes = this.attributes;
4063 var control = attributes['points']['control'] || [];
4067 if (control.length > 0 && !(control[0] instanceof Array)) {
4068 control = [control];
4071 for (i = 0,len = control.length; i < len; ++i) {
4072 tmp[i] = control[i];
4077 Roo.fly(el).position();
4079 if (isset(attributes['points']['from'])) {
4080 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4083 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4086 start = this.getAttribute('points');
4089 if (isset(attributes['points']['to'])) {
4090 end = translateValues.call(this, attributes['points']['to'], start);
4092 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4093 for (i = 0,len = control.length; i < len; ++i) {
4094 control[i] = translateValues.call(this, control[i], start);
4098 } else if (isset(attributes['points']['by'])) {
4099 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4101 for (i = 0,len = control.length; i < len; ++i) {
4102 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4106 this.runtimeAttributes[attr] = [start];
4108 if (control.length > 0) {
4109 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4112 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4115 superclass.setRuntimeAttribute.call(this, attr);
4119 var translateValues = function(val, start) {
4120 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4121 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4126 var isset = function(prop) {
4127 return (typeof prop !== 'undefined');
4131 * Portions of this file are based on pieces of Yahoo User Interface Library
4132 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4133 * YUI licensed under the BSD License:
4134 * http://developer.yahoo.net/yui/license.txt
4135 * <script type="text/javascript">
4139 Roo.lib.Scroll = function(el, attributes, duration, method) {
4141 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4145 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4149 var superclass = Y.Scroll.superclass;
4150 var proto = Y.Scroll.prototype;
4152 proto.toString = function() {
4153 var el = this.getEl();
4154 var id = el.id || el.tagName;
4155 return ("Scroll " + id);
4158 proto.doMethod = function(attr, start, end) {
4161 if (attr == 'scroll') {
4163 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4164 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4168 val = superclass.doMethod.call(this, attr, start, end);
4173 proto.getAttribute = function(attr) {
4175 var el = this.getEl();
4177 if (attr == 'scroll') {
4178 val = [ el.scrollLeft, el.scrollTop ];
4180 val = superclass.getAttribute.call(this, attr);
4186 proto.setAttribute = function(attr, val, unit) {
4187 var el = this.getEl();
4189 if (attr == 'scroll') {
4190 el.scrollLeft = val[0];
4191 el.scrollTop = val[1];
4193 superclass.setAttribute.call(this, attr, val, unit);
4199 * Ext JS Library 1.1.1
4200 * Copyright(c) 2006-2007, Ext JS, LLC.
4202 * Originally Released Under LGPL - original licence link has changed is not relivant.
4205 * <script type="text/javascript">
4209 // nasty IE9 hack - what a pile of crap that is..
4211 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4212 Range.prototype.createContextualFragment = function (html) {
4213 var doc = window.document;
4214 var container = doc.createElement("div");
4215 container.innerHTML = html;
4216 var frag = doc.createDocumentFragment(), n;
4217 while ((n = container.firstChild)) {
4218 frag.appendChild(n);
4225 * @class Roo.DomHelper
4226 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4227 * 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>.
4230 Roo.DomHelper = function(){
4231 var tempTableEl = null;
4232 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4233 var tableRe = /^table|tbody|tr|td$/i;
4235 // build as innerHTML where available
4237 var createHtml = function(o){
4238 if(typeof o == 'string'){
4247 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4248 if(attr == "style"){
4250 if(typeof s == "function"){
4253 if(typeof s == "string"){
4254 b += ' style="' + s + '"';
4255 }else if(typeof s == "object"){
4258 if(typeof s[key] != "function"){
4259 b += key + ":" + s[key] + ";";
4266 b += ' class="' + o["cls"] + '"';
4267 }else if(attr == "htmlFor"){
4268 b += ' for="' + o["htmlFor"] + '"';
4270 b += " " + attr + '="' + o[attr] + '"';
4274 if(emptyTags.test(o.tag)){
4278 var cn = o.children || o.cn;
4280 //http://bugs.kde.org/show_bug.cgi?id=71506
4281 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4282 for(var i = 0, len = cn.length; i < len; i++) {
4283 b += createHtml(cn[i], b);
4286 b += createHtml(cn, b);
4292 b += "</" + o.tag + ">";
4299 var createDom = function(o, parentNode){
4301 // defininition craeted..
4303 if (o.ns && o.ns != 'html') {
4305 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4306 xmlns[o.ns] = o.xmlns;
4309 if (typeof(xmlns[o.ns]) == 'undefined') {
4310 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4316 if (typeof(o) == 'string') {
4317 return parentNode.appendChild(document.createTextNode(o));
4319 o.tag = o.tag || div;
4320 if (o.ns && Roo.isIE) {
4322 o.tag = o.ns + ':' + o.tag;
4325 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4326 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4329 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4330 attr == "style" || typeof o[attr] == "function") { continue; }
4332 if(attr=="cls" && Roo.isIE){
4333 el.className = o["cls"];
4335 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4341 Roo.DomHelper.applyStyles(el, o.style);
4342 var cn = o.children || o.cn;
4344 //http://bugs.kde.org/show_bug.cgi?id=71506
4345 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4346 for(var i = 0, len = cn.length; i < len; i++) {
4347 createDom(cn[i], el);
4354 el.innerHTML = o.html;
4357 parentNode.appendChild(el);
4362 var ieTable = function(depth, s, h, e){
4363 tempTableEl.innerHTML = [s, h, e].join('');
4364 var i = -1, el = tempTableEl;
4365 while(++i < depth && el.firstChild){
4371 // kill repeat to save bytes
4375 tbe = '</tbody>'+te,
4381 * Nasty code for IE's broken table implementation
4383 var insertIntoTable = function(tag, where, el, html){
4385 tempTableEl = document.createElement('div');
4390 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4393 if(where == 'beforebegin'){
4397 before = el.nextSibling;
4400 node = ieTable(4, trs, html, tre);
4402 else if(tag == 'tr'){
4403 if(where == 'beforebegin'){
4406 node = ieTable(3, tbs, html, tbe);
4407 } else if(where == 'afterend'){
4408 before = el.nextSibling;
4410 node = ieTable(3, tbs, html, tbe);
4411 } else{ // INTO a TR
4412 if(where == 'afterbegin'){
4413 before = el.firstChild;
4415 node = ieTable(4, trs, html, tre);
4417 } else if(tag == 'tbody'){
4418 if(where == 'beforebegin'){
4421 node = ieTable(2, ts, html, te);
4422 } else if(where == 'afterend'){
4423 before = el.nextSibling;
4425 node = ieTable(2, ts, html, te);
4427 if(where == 'afterbegin'){
4428 before = el.firstChild;
4430 node = ieTable(3, tbs, html, tbe);
4433 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4436 if(where == 'afterbegin'){
4437 before = el.firstChild;
4439 node = ieTable(2, ts, html, te);
4441 el.insertBefore(node, before);
4446 /** True to force the use of DOM instead of html fragments @type Boolean */
4450 * Returns the markup for the passed Element(s) config
4451 * @param {Object} o The Dom object spec (and children)
4454 markup : function(o){
4455 return createHtml(o);
4459 * Applies a style specification to an element
4460 * @param {String/HTMLElement} el The element to apply styles to
4461 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4462 * a function which returns such a specification.
4464 applyStyles : function(el, styles){
4467 if(typeof styles == "string"){
4468 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4470 while ((matches = re.exec(styles)) != null){
4471 el.setStyle(matches[1], matches[2]);
4473 }else if (typeof styles == "object"){
4474 for (var style in styles){
4475 el.setStyle(style, styles[style]);
4477 }else if (typeof styles == "function"){
4478 Roo.DomHelper.applyStyles(el, styles.call());
4484 * Inserts an HTML fragment into the Dom
4485 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4486 * @param {HTMLElement} el The context element
4487 * @param {String} html The HTML fragmenet
4488 * @return {HTMLElement} The new node
4490 insertHtml : function(where, el, html){
4491 where = where.toLowerCase();
4492 if(el.insertAdjacentHTML){
4493 if(tableRe.test(el.tagName)){
4495 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4501 el.insertAdjacentHTML('BeforeBegin', html);
4502 return el.previousSibling;
4504 el.insertAdjacentHTML('AfterBegin', html);
4505 return el.firstChild;
4507 el.insertAdjacentHTML('BeforeEnd', html);
4508 return el.lastChild;
4510 el.insertAdjacentHTML('AfterEnd', html);
4511 return el.nextSibling;
4513 throw 'Illegal insertion point -> "' + where + '"';
4515 var range = el.ownerDocument.createRange();
4519 range.setStartBefore(el);
4520 frag = range.createContextualFragment(html);
4521 el.parentNode.insertBefore(frag, el);
4522 return el.previousSibling;
4525 range.setStartBefore(el.firstChild);
4526 frag = range.createContextualFragment(html);
4527 el.insertBefore(frag, el.firstChild);
4528 return el.firstChild;
4530 el.innerHTML = html;
4531 return el.firstChild;
4535 range.setStartAfter(el.lastChild);
4536 frag = range.createContextualFragment(html);
4537 el.appendChild(frag);
4538 return el.lastChild;
4540 el.innerHTML = html;
4541 return el.lastChild;
4544 range.setStartAfter(el);
4545 frag = range.createContextualFragment(html);
4546 el.parentNode.insertBefore(frag, el.nextSibling);
4547 return el.nextSibling;
4549 throw 'Illegal insertion point -> "' + where + '"';
4553 * Creates new Dom element(s) and inserts them before el
4554 * @param {String/HTMLElement/Element} el The context element
4555 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4556 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4557 * @return {HTMLElement/Roo.Element} The new node
4559 insertBefore : function(el, o, returnElement){
4560 return this.doInsert(el, o, returnElement, "beforeBegin");
4564 * Creates new Dom element(s) and inserts them after el
4565 * @param {String/HTMLElement/Element} el The context element
4566 * @param {Object} o The Dom object spec (and children)
4567 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4568 * @return {HTMLElement/Roo.Element} The new node
4570 insertAfter : function(el, o, returnElement){
4571 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4575 * Creates new Dom element(s) and inserts them as the first child of el
4576 * @param {String/HTMLElement/Element} el The context element
4577 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4578 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4579 * @return {HTMLElement/Roo.Element} The new node
4581 insertFirst : function(el, o, returnElement){
4582 return this.doInsert(el, o, returnElement, "afterBegin");
4586 doInsert : function(el, o, returnElement, pos, sibling){
4587 el = Roo.getDom(el);
4589 if(this.useDom || o.ns){
4590 newNode = createDom(o, null);
4591 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4593 var html = createHtml(o);
4594 newNode = this.insertHtml(pos, el, html);
4596 return returnElement ? Roo.get(newNode, true) : newNode;
4600 * Creates new Dom element(s) and appends them to el
4601 * @param {String/HTMLElement/Element} el The context element
4602 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4603 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4604 * @return {HTMLElement/Roo.Element} The new node
4606 append : function(el, o, returnElement){
4607 el = Roo.getDom(el);
4609 if(this.useDom || o.ns){
4610 newNode = createDom(o, null);
4611 el.appendChild(newNode);
4613 var html = createHtml(o);
4614 newNode = this.insertHtml("beforeEnd", el, html);
4616 return returnElement ? Roo.get(newNode, true) : newNode;
4620 * Creates new Dom element(s) and overwrites the contents of el with them
4621 * @param {String/HTMLElement/Element} el The context element
4622 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4623 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4624 * @return {HTMLElement/Roo.Element} The new node
4626 overwrite : function(el, o, returnElement){
4627 el = Roo.getDom(el);
4630 while (el.childNodes.length) {
4631 el.removeChild(el.firstChild);
4635 el.innerHTML = createHtml(o);
4638 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4642 * Creates a new Roo.DomHelper.Template from the Dom object spec
4643 * @param {Object} o The Dom object spec (and children)
4644 * @return {Roo.DomHelper.Template} The new template
4646 createTemplate : function(o){
4647 var html = createHtml(o);
4648 return new Roo.Template(html);
4654 * Ext JS Library 1.1.1
4655 * Copyright(c) 2006-2007, Ext JS, LLC.
4657 * Originally Released Under LGPL - original licence link has changed is not relivant.
4660 * <script type="text/javascript">
4664 * @class Roo.Template
4665 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4666 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4669 var t = new Roo.Template({
4670 html : '<div name="{id}">' +
4671 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4673 myformat: function (value, allValues) {
4674 return 'XX' + value;
4677 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4679 * For more information see this blog post with examples:
4680 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4681 - Create Elements using DOM, HTML fragments and Templates</a>.
4683 * @param {Object} cfg - Configuration object.
4685 Roo.Template = function(cfg){
4687 if(cfg instanceof Array){
4689 }else if(arguments.length > 1){
4690 cfg = Array.prototype.join.call(arguments, "");
4694 if (typeof(cfg) == 'object') {
4705 Roo.Template.prototype = {
4708 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
4714 * @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..
4715 * it should be fixed so that template is observable...
4719 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4727 * Returns an HTML fragment of this template with the specified values applied.
4728 * @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'})
4729 * @return {String} The HTML fragment
4734 applyTemplate : function(values){
4735 //Roo.log(["applyTemplate", values]);
4739 return this.compiled(values);
4741 var useF = this.disableFormats !== true;
4742 var fm = Roo.util.Format, tpl = this;
4743 var fn = function(m, name, format, args){
4745 if(format.substr(0, 5) == "this."){
4746 return tpl.call(format.substr(5), values[name], values);
4749 // quoted values are required for strings in compiled templates,
4750 // but for non compiled we need to strip them
4751 // quoted reversed for jsmin
4752 var re = /^\s*['"](.*)["']\s*$/;
4753 args = args.split(',');
4754 for(var i = 0, len = args.length; i < len; i++){
4755 args[i] = args[i].replace(re, "$1");
4757 args = [values[name]].concat(args);
4759 args = [values[name]];
4761 return fm[format].apply(fm, args);
4764 return values[name] !== undefined ? values[name] : "";
4767 return this.html.replace(this.re, fn);
4785 this.loading = true;
4786 this.compiled = false;
4788 var cx = new Roo.data.Connection();
4792 success : function (response) {
4796 _t.set(response.responseText,true);
4802 failure : function(response) {
4803 Roo.log("Template failed to load from " + _t.url);
4810 * Sets the HTML used as the template and optionally compiles it.
4811 * @param {String} html
4812 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4813 * @return {Roo.Template} this
4815 set : function(html, compile){
4817 this.compiled = false;
4825 * True to disable format functions (defaults to false)
4828 disableFormats : false,
4831 * The regular expression used to match template variables
4835 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4838 * Compiles the template into an internal function, eliminating the RegEx overhead.
4839 * @return {Roo.Template} this
4841 compile : function(){
4842 var fm = Roo.util.Format;
4843 var useF = this.disableFormats !== true;
4844 var sep = Roo.isGecko ? "+" : ",";
4845 var fn = function(m, name, format, args){
4847 args = args ? ',' + args : "";
4848 if(format.substr(0, 5) != "this."){
4849 format = "fm." + format + '(';
4851 format = 'this.call("'+ format.substr(5) + '", ';
4855 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4857 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4860 // branched to use + in gecko and [].join() in others
4862 body = "this.compiled = function(values){ return '" +
4863 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4866 body = ["this.compiled = function(values){ return ['"];
4867 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4868 body.push("'].join('');};");
4869 body = body.join('');
4879 // private function used to call members
4880 call : function(fnName, value, allValues){
4881 return this[fnName](value, allValues);
4885 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4886 * @param {String/HTMLElement/Roo.Element} el The context element
4887 * @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'})
4888 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4889 * @return {HTMLElement/Roo.Element} The new node or Element
4891 insertFirst: function(el, values, returnElement){
4892 return this.doInsert('afterBegin', el, values, returnElement);
4896 * Applies the supplied values to the template and inserts the new node(s) before el.
4897 * @param {String/HTMLElement/Roo.Element} el The context element
4898 * @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'})
4899 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4900 * @return {HTMLElement/Roo.Element} The new node or Element
4902 insertBefore: function(el, values, returnElement){
4903 return this.doInsert('beforeBegin', el, values, returnElement);
4907 * Applies the supplied values to the template and inserts the new node(s) after el.
4908 * @param {String/HTMLElement/Roo.Element} el The context element
4909 * @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'})
4910 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4911 * @return {HTMLElement/Roo.Element} The new node or Element
4913 insertAfter : function(el, values, returnElement){
4914 return this.doInsert('afterEnd', el, values, returnElement);
4918 * Applies the supplied values to the template and appends the new node(s) to el.
4919 * @param {String/HTMLElement/Roo.Element} el The context element
4920 * @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'})
4921 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4922 * @return {HTMLElement/Roo.Element} The new node or Element
4924 append : function(el, values, returnElement){
4925 return this.doInsert('beforeEnd', el, values, returnElement);
4928 doInsert : function(where, el, values, returnEl){
4929 el = Roo.getDom(el);
4930 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4931 return returnEl ? Roo.get(newNode, true) : newNode;
4935 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4936 * @param {String/HTMLElement/Roo.Element} el The context element
4937 * @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'})
4938 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4939 * @return {HTMLElement/Roo.Element} The new node or Element
4941 overwrite : function(el, values, returnElement){
4942 el = Roo.getDom(el);
4943 el.innerHTML = this.applyTemplate(values);
4944 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4948 * Alias for {@link #applyTemplate}
4951 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4954 Roo.DomHelper.Template = Roo.Template;
4957 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4958 * @param {String/HTMLElement} el A DOM element or its id
4959 * @returns {Roo.Template} The created template
4962 Roo.Template.from = function(el){
4963 el = Roo.getDom(el);
4964 return new Roo.Template(el.value || el.innerHTML);
4967 * Ext JS Library 1.1.1
4968 * Copyright(c) 2006-2007, Ext JS, LLC.
4970 * Originally Released Under LGPL - original licence link has changed is not relivant.
4973 * <script type="text/javascript">
4978 * This is code is also distributed under MIT license for use
4979 * with jQuery and prototype JavaScript libraries.
4982 * @class Roo.DomQuery
4983 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).
4985 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>
4988 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.
4990 <h4>Element Selectors:</h4>
4992 <li> <b>*</b> any element</li>
4993 <li> <b>E</b> an element with the tag E</li>
4994 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4995 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4996 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4997 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4999 <h4>Attribute Selectors:</h4>
5000 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5002 <li> <b>E[foo]</b> has an attribute "foo"</li>
5003 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5004 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5005 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5006 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5007 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5008 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5010 <h4>Pseudo Classes:</h4>
5012 <li> <b>E:first-child</b> E is the first child of its parent</li>
5013 <li> <b>E:last-child</b> E is the last child of its parent</li>
5014 <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>
5015 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5016 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5017 <li> <b>E:only-child</b> E is the only child of its parent</li>
5018 <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>
5019 <li> <b>E:first</b> the first E in the resultset</li>
5020 <li> <b>E:last</b> the last E in the resultset</li>
5021 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5022 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5023 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5024 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5025 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5026 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5027 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5028 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5029 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5031 <h4>CSS Value Selectors:</h4>
5033 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5034 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5035 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5036 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5037 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5038 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5042 Roo.DomQuery = function(){
5043 var cache = {}, simpleCache = {}, valueCache = {};
5044 var nonSpace = /\S/;
5045 var trimRe = /^\s+|\s+$/g;
5046 var tplRe = /\{(\d+)\}/g;
5047 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5048 var tagTokenRe = /^(#)?([\w-\*]+)/;
5049 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5051 function child(p, index){
5053 var n = p.firstChild;
5055 if(n.nodeType == 1){
5066 while((n = n.nextSibling) && n.nodeType != 1);
5071 while((n = n.previousSibling) && n.nodeType != 1);
5075 function children(d){
5076 var n = d.firstChild, ni = -1;
5078 var nx = n.nextSibling;
5079 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5089 function byClassName(c, a, v){
5093 var r = [], ri = -1, cn;
5094 for(var i = 0, ci; ci = c[i]; i++){
5098 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5099 +' ').indexOf(v) != -1){
5106 function attrValue(n, attr){
5107 if(!n.tagName && typeof n.length != "undefined"){
5116 if(attr == "class" || attr == "className"){
5117 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5119 return n.getAttribute(attr) || n[attr];
5123 function getNodes(ns, mode, tagName){
5124 var result = [], ri = -1, cs;
5128 tagName = tagName || "*";
5129 if(typeof ns.getElementsByTagName != "undefined"){
5133 for(var i = 0, ni; ni = ns[i]; i++){
5134 cs = ni.getElementsByTagName(tagName);
5135 for(var j = 0, ci; ci = cs[j]; j++){
5139 }else if(mode == "/" || mode == ">"){
5140 var utag = tagName.toUpperCase();
5141 for(var i = 0, ni, cn; ni = ns[i]; i++){
5142 cn = ni.children || ni.childNodes;
5143 for(var j = 0, cj; cj = cn[j]; j++){
5144 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5149 }else if(mode == "+"){
5150 var utag = tagName.toUpperCase();
5151 for(var i = 0, n; n = ns[i]; i++){
5152 while((n = n.nextSibling) && n.nodeType != 1);
5153 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5157 }else if(mode == "~"){
5158 for(var i = 0, n; n = ns[i]; i++){
5159 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5168 function concat(a, b){
5172 for(var i = 0, l = b.length; i < l; i++){
5178 function byTag(cs, tagName){
5179 if(cs.tagName || cs == document){
5185 var r = [], ri = -1;
5186 tagName = tagName.toLowerCase();
5187 for(var i = 0, ci; ci = cs[i]; i++){
5188 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5195 function byId(cs, attr, id){
5196 if(cs.tagName || cs == document){
5202 var r = [], ri = -1;
5203 for(var i = 0,ci; ci = cs[i]; i++){
5204 if(ci && ci.id == id){
5212 function byAttribute(cs, attr, value, op, custom){
5213 var r = [], ri = -1, st = custom=="{";
5214 var f = Roo.DomQuery.operators[op];
5215 for(var i = 0, ci; ci = cs[i]; i++){
5218 a = Roo.DomQuery.getStyle(ci, attr);
5220 else if(attr == "class" || attr == "className"){
5221 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
5222 }else if(attr == "for"){
5224 }else if(attr == "href"){
5225 a = ci.getAttribute("href", 2);
5227 a = ci.getAttribute(attr);
5229 if((f && f(a, value)) || (!f && a)){
5236 function byPseudo(cs, name, value){
5237 return Roo.DomQuery.pseudos[name](cs, value);
5240 // This is for IE MSXML which does not support expandos.
5241 // IE runs the same speed using setAttribute, however FF slows way down
5242 // and Safari completely fails so they need to continue to use expandos.
5243 var isIE = window.ActiveXObject ? true : false;
5245 // this eval is stop the compressor from
5246 // renaming the variable to something shorter
5248 /** eval:var:batch */
5253 function nodupIEXml(cs){
5255 cs[0].setAttribute("_nodup", d);
5257 for(var i = 1, len = cs.length; i < len; i++){
5259 if(!c.getAttribute("_nodup") != d){
5260 c.setAttribute("_nodup", d);
5264 for(var i = 0, len = cs.length; i < len; i++){
5265 cs[i].removeAttribute("_nodup");
5274 var len = cs.length, c, i, r = cs, cj, ri = -1;
5275 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5278 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5279 return nodupIEXml(cs);
5283 for(i = 1; c = cs[i]; i++){
5288 for(var j = 0; j < i; j++){
5291 for(j = i+1; cj = cs[j]; j++){
5303 function quickDiffIEXml(c1, c2){
5305 for(var i = 0, len = c1.length; i < len; i++){
5306 c1[i].setAttribute("_qdiff", d);
5309 for(var i = 0, len = c2.length; i < len; i++){
5310 if(c2[i].getAttribute("_qdiff") != d){
5311 r[r.length] = c2[i];
5314 for(var i = 0, len = c1.length; i < len; i++){
5315 c1[i].removeAttribute("_qdiff");
5320 function quickDiff(c1, c2){
5321 var len1 = c1.length;
5325 if(isIE && c1[0].selectSingleNode){
5326 return quickDiffIEXml(c1, c2);
5329 for(var i = 0; i < len1; i++){
5333 for(var i = 0, len = c2.length; i < len; i++){
5334 if(c2[i]._qdiff != d){
5335 r[r.length] = c2[i];
5341 function quickId(ns, mode, root, id){
5343 var d = root.ownerDocument || root;
5344 return d.getElementById(id);
5346 ns = getNodes(ns, mode, "*");
5347 return byId(ns, null, id);
5351 getStyle : function(el, name){
5352 return Roo.fly(el).getStyle(name);
5355 * Compiles a selector/xpath query into a reusable function. The returned function
5356 * takes one parameter "root" (optional), which is the context node from where the query should start.
5357 * @param {String} selector The selector/xpath query
5358 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5359 * @return {Function}
5361 compile : function(path, type){
5362 type = type || "select";
5364 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5365 var q = path, mode, lq;
5366 var tk = Roo.DomQuery.matchers;
5367 var tklen = tk.length;
5370 // accept leading mode switch
5371 var lmode = q.match(modeRe);
5372 if(lmode && lmode[1]){
5373 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5374 q = q.replace(lmode[1], "");
5376 // strip leading slashes
5377 while(path.substr(0, 1)=="/"){
5378 path = path.substr(1);
5381 while(q && lq != q){
5383 var tm = q.match(tagTokenRe);
5384 if(type == "select"){
5387 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5389 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5391 q = q.replace(tm[0], "");
5392 }else if(q.substr(0, 1) != '@'){
5393 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5398 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5400 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5402 q = q.replace(tm[0], "");
5405 while(!(mm = q.match(modeRe))){
5406 var matched = false;
5407 for(var j = 0; j < tklen; j++){
5409 var m = q.match(t.re);
5411 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5414 q = q.replace(m[0], "");
5419 // prevent infinite loop on bad selector
5421 throw 'Error parsing selector, parsing failed at "' + q + '"';
5425 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5426 q = q.replace(mm[1], "");
5429 fn[fn.length] = "return nodup(n);\n}";
5432 * list of variables that need from compression as they are used by eval.
5442 * eval:var:byClassName
5444 * eval:var:byAttribute
5445 * eval:var:attrValue
5453 * Selects a group of elements.
5454 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5455 * @param {Node} root (optional) The start of the query (defaults to document).
5458 select : function(path, root, type){
5459 if(!root || root == document){
5462 if(typeof root == "string"){
5463 root = document.getElementById(root);
5465 var paths = path.split(",");
5467 for(var i = 0, len = paths.length; i < len; i++){
5468 var p = paths[i].replace(trimRe, "");
5470 cache[p] = Roo.DomQuery.compile(p);
5472 throw p + " is not a valid selector";
5475 var result = cache[p](root);
5476 if(result && result != document){
5477 results = results.concat(result);
5480 if(paths.length > 1){
5481 return nodup(results);
5487 * Selects a single element.
5488 * @param {String} selector The selector/xpath query
5489 * @param {Node} root (optional) The start of the query (defaults to document).
5492 selectNode : function(path, root){
5493 return Roo.DomQuery.select(path, root)[0];
5497 * Selects the value of a node, optionally replacing null with the defaultValue.
5498 * @param {String} selector The selector/xpath query
5499 * @param {Node} root (optional) The start of the query (defaults to document).
5500 * @param {String} defaultValue
5502 selectValue : function(path, root, defaultValue){
5503 path = path.replace(trimRe, "");
5504 if(!valueCache[path]){
5505 valueCache[path] = Roo.DomQuery.compile(path, "select");
5507 var n = valueCache[path](root);
5508 n = n[0] ? n[0] : n;
5509 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5510 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5514 * Selects the value of a node, parsing integers and floats.
5515 * @param {String} selector The selector/xpath query
5516 * @param {Node} root (optional) The start of the query (defaults to document).
5517 * @param {Number} defaultValue
5520 selectNumber : function(path, root, defaultValue){
5521 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5522 return parseFloat(v);
5526 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5527 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5528 * @param {String} selector The simple selector to test
5531 is : function(el, ss){
5532 if(typeof el == "string"){
5533 el = document.getElementById(el);
5535 var isArray = (el instanceof Array);
5536 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5537 return isArray ? (result.length == el.length) : (result.length > 0);
5541 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5542 * @param {Array} el An array of elements to filter
5543 * @param {String} selector The simple selector to test
5544 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5545 * the selector instead of the ones that match
5548 filter : function(els, ss, nonMatches){
5549 ss = ss.replace(trimRe, "");
5550 if(!simpleCache[ss]){
5551 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5553 var result = simpleCache[ss](els);
5554 return nonMatches ? quickDiff(result, els) : result;
5558 * Collection of matching regular expressions and code snippets.
5562 select: 'n = byClassName(n, null, " {1} ");'
5564 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5565 select: 'n = byPseudo(n, "{1}", "{2}");'
5567 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5568 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5571 select: 'n = byId(n, null, "{1}");'
5574 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5579 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5580 * 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, > <.
5583 "=" : function(a, v){
5586 "!=" : function(a, v){
5589 "^=" : function(a, v){
5590 return a && a.substr(0, v.length) == v;
5592 "$=" : function(a, v){
5593 return a && a.substr(a.length-v.length) == v;
5595 "*=" : function(a, v){
5596 return a && a.indexOf(v) !== -1;
5598 "%=" : function(a, v){
5599 return (a % v) == 0;
5601 "|=" : function(a, v){
5602 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5604 "~=" : function(a, v){
5605 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5610 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5611 * and the argument (if any) supplied in the selector.
5614 "first-child" : function(c){
5615 var r = [], ri = -1, n;
5616 for(var i = 0, ci; ci = n = c[i]; i++){
5617 while((n = n.previousSibling) && n.nodeType != 1);
5625 "last-child" : function(c){
5626 var r = [], ri = -1, n;
5627 for(var i = 0, ci; ci = n = c[i]; i++){
5628 while((n = n.nextSibling) && n.nodeType != 1);
5636 "nth-child" : function(c, a) {
5637 var r = [], ri = -1;
5638 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5639 var f = (m[1] || 1) - 0, l = m[2] - 0;
5640 for(var i = 0, n; n = c[i]; i++){
5641 var pn = n.parentNode;
5642 if (batch != pn._batch) {
5644 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5645 if(cn.nodeType == 1){
5652 if (l == 0 || n.nodeIndex == l){
5655 } else if ((n.nodeIndex + l) % f == 0){
5663 "only-child" : function(c){
5664 var r = [], ri = -1;;
5665 for(var i = 0, ci; ci = c[i]; i++){
5666 if(!prev(ci) && !next(ci)){
5673 "empty" : function(c){
5674 var r = [], ri = -1;
5675 for(var i = 0, ci; ci = c[i]; i++){
5676 var cns = ci.childNodes, j = 0, cn, empty = true;
5679 if(cn.nodeType == 1 || cn.nodeType == 3){
5691 "contains" : function(c, v){
5692 var r = [], ri = -1;
5693 for(var i = 0, ci; ci = c[i]; i++){
5694 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5701 "nodeValue" : function(c, v){
5702 var r = [], ri = -1;
5703 for(var i = 0, ci; ci = c[i]; i++){
5704 if(ci.firstChild && ci.firstChild.nodeValue == v){
5711 "checked" : function(c){
5712 var r = [], ri = -1;
5713 for(var i = 0, ci; ci = c[i]; i++){
5714 if(ci.checked == true){
5721 "not" : function(c, ss){
5722 return Roo.DomQuery.filter(c, ss, true);
5725 "odd" : function(c){
5726 return this["nth-child"](c, "odd");
5729 "even" : function(c){
5730 return this["nth-child"](c, "even");
5733 "nth" : function(c, a){
5734 return c[a-1] || [];
5737 "first" : function(c){
5741 "last" : function(c){
5742 return c[c.length-1] || [];
5745 "has" : function(c, ss){
5746 var s = Roo.DomQuery.select;
5747 var r = [], ri = -1;
5748 for(var i = 0, ci; ci = c[i]; i++){
5749 if(s(ss, ci).length > 0){
5756 "next" : function(c, ss){
5757 var is = Roo.DomQuery.is;
5758 var r = [], ri = -1;
5759 for(var i = 0, ci; ci = c[i]; i++){
5768 "prev" : function(c, ss){
5769 var is = Roo.DomQuery.is;
5770 var r = [], ri = -1;
5771 for(var i = 0, ci; ci = c[i]; i++){
5784 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5785 * @param {String} path The selector/xpath query
5786 * @param {Node} root (optional) The start of the query (defaults to document).
5791 Roo.query = Roo.DomQuery.select;
5794 * Ext JS Library 1.1.1
5795 * Copyright(c) 2006-2007, Ext JS, LLC.
5797 * Originally Released Under LGPL - original licence link has changed is not relivant.
5800 * <script type="text/javascript">
5804 * @class Roo.util.Observable
5805 * Base class that provides a common interface for publishing events. Subclasses are expected to
5806 * to have a property "events" with all the events defined.<br>
5809 Employee = function(name){
5816 Roo.extend(Employee, Roo.util.Observable);
5818 * @param {Object} config properties to use (incuding events / listeners)
5821 Roo.util.Observable = function(cfg){
5824 this.addEvents(cfg.events || {});
5826 delete cfg.events; // make sure
5829 Roo.apply(this, cfg);
5832 this.on(this.listeners);
5833 delete this.listeners;
5836 Roo.util.Observable.prototype = {
5838 * @cfg {Object} listeners list of events and functions to call for this object,
5842 'click' : function(e) {
5852 * Fires the specified event with the passed parameters (minus the event name).
5853 * @param {String} eventName
5854 * @param {Object...} args Variable number of parameters are passed to handlers
5855 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5857 fireEvent : function(){
5858 var ce = this.events[arguments[0].toLowerCase()];
5859 if(typeof ce == "object"){
5860 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5867 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5870 * Appends an event handler to this component
5871 * @param {String} eventName The type of event to listen for
5872 * @param {Function} handler The method the event invokes
5873 * @param {Object} scope (optional) The scope in which to execute the handler
5874 * function. The handler function's "this" context.
5875 * @param {Object} options (optional) An object containing handler configuration
5876 * properties. This may contain any of the following properties:<ul>
5877 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5878 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5879 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5880 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5881 * by the specified number of milliseconds. If the event fires again within that time, the original
5882 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5885 * <b>Combining Options</b><br>
5886 * Using the options argument, it is possible to combine different types of listeners:<br>
5888 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5890 el.on('click', this.onClick, this, {
5897 * <b>Attaching multiple handlers in 1 call</b><br>
5898 * The method also allows for a single argument to be passed which is a config object containing properties
5899 * which specify multiple handlers.
5908 fn: this.onMouseOver,
5912 fn: this.onMouseOut,
5918 * Or a shorthand syntax which passes the same scope object to all handlers:
5921 'click': this.onClick,
5922 'mouseover': this.onMouseOver,
5923 'mouseout': this.onMouseOut,
5928 addListener : function(eventName, fn, scope, o){
5929 if(typeof eventName == "object"){
5932 if(this.filterOptRe.test(e)){
5935 if(typeof o[e] == "function"){
5937 this.addListener(e, o[e], o.scope, o);
5939 // individual options
5940 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5945 o = (!o || typeof o == "boolean") ? {} : o;
5946 eventName = eventName.toLowerCase();
5947 var ce = this.events[eventName] || true;
5948 if(typeof ce == "boolean"){
5949 ce = new Roo.util.Event(this, eventName);
5950 this.events[eventName] = ce;
5952 ce.addListener(fn, scope, o);
5956 * Removes a listener
5957 * @param {String} eventName The type of event to listen for
5958 * @param {Function} handler The handler to remove
5959 * @param {Object} scope (optional) The scope (this object) for the handler
5961 removeListener : function(eventName, fn, scope){
5962 var ce = this.events[eventName.toLowerCase()];
5963 if(typeof ce == "object"){
5964 ce.removeListener(fn, scope);
5969 * Removes all listeners for this object
5971 purgeListeners : function(){
5972 for(var evt in this.events){
5973 if(typeof this.events[evt] == "object"){
5974 this.events[evt].clearListeners();
5979 relayEvents : function(o, events){
5980 var createHandler = function(ename){
5983 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5986 for(var i = 0, len = events.length; i < len; i++){
5987 var ename = events[i];
5988 if(!this.events[ename]){
5989 this.events[ename] = true;
5991 o.on(ename, createHandler(ename), this);
5996 * Used to define events on this Observable
5997 * @param {Object} object The object with the events defined
5999 addEvents : function(o){
6003 Roo.applyIf(this.events, o);
6007 * Checks to see if this object has any listeners for a specified event
6008 * @param {String} eventName The name of the event to check for
6009 * @return {Boolean} True if the event is being listened for, else false
6011 hasListener : function(eventName){
6012 var e = this.events[eventName];
6013 return typeof e == "object" && e.listeners.length > 0;
6017 * Appends an event handler to this element (shorthand for addListener)
6018 * @param {String} eventName The type of event to listen for
6019 * @param {Function} handler The method the event invokes
6020 * @param {Object} scope (optional) The scope in which to execute the handler
6021 * function. The handler function's "this" context.
6022 * @param {Object} options (optional)
6025 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6027 * Removes a listener (shorthand for removeListener)
6028 * @param {String} eventName The type of event to listen for
6029 * @param {Function} handler The handler to remove
6030 * @param {Object} scope (optional) The scope (this object) for the handler
6033 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6036 * Starts capture on the specified Observable. All events will be passed
6037 * to the supplied function with the event name + standard signature of the event
6038 * <b>before</b> the event is fired. If the supplied function returns false,
6039 * the event will not fire.
6040 * @param {Observable} o The Observable to capture
6041 * @param {Function} fn The function to call
6042 * @param {Object} scope (optional) The scope (this object) for the fn
6045 Roo.util.Observable.capture = function(o, fn, scope){
6046 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6050 * Removes <b>all</b> added captures from the Observable.
6051 * @param {Observable} o The Observable to release
6054 Roo.util.Observable.releaseCapture = function(o){
6055 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6060 var createBuffered = function(h, o, scope){
6061 var task = new Roo.util.DelayedTask();
6063 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6067 var createSingle = function(h, e, fn, scope){
6069 e.removeListener(fn, scope);
6070 return h.apply(scope, arguments);
6074 var createDelayed = function(h, o, scope){
6076 var args = Array.prototype.slice.call(arguments, 0);
6077 setTimeout(function(){
6078 h.apply(scope, args);
6083 Roo.util.Event = function(obj, name){
6086 this.listeners = [];
6089 Roo.util.Event.prototype = {
6090 addListener : function(fn, scope, options){
6091 var o = options || {};
6092 scope = scope || this.obj;
6093 if(!this.isListening(fn, scope)){
6094 var l = {fn: fn, scope: scope, options: o};
6097 h = createDelayed(h, o, scope);
6100 h = createSingle(h, this, fn, scope);
6103 h = createBuffered(h, o, scope);
6106 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6107 this.listeners.push(l);
6109 this.listeners = this.listeners.slice(0);
6110 this.listeners.push(l);
6115 findListener : function(fn, scope){
6116 scope = scope || this.obj;
6117 var ls = this.listeners;
6118 for(var i = 0, len = ls.length; i < len; i++){
6120 if(l.fn == fn && l.scope == scope){
6127 isListening : function(fn, scope){
6128 return this.findListener(fn, scope) != -1;
6131 removeListener : function(fn, scope){
6133 if((index = this.findListener(fn, scope)) != -1){
6135 this.listeners.splice(index, 1);
6137 this.listeners = this.listeners.slice(0);
6138 this.listeners.splice(index, 1);
6145 clearListeners : function(){
6146 this.listeners = [];
6150 var ls = this.listeners, scope, len = ls.length;
6153 var args = Array.prototype.slice.call(arguments, 0);
6154 for(var i = 0; i < len; i++){
6156 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6157 this.firing = false;
6161 this.firing = false;
6168 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6175 * @class Roo.Document
6176 * @extends Roo.util.Observable
6177 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6179 * @param {Object} config the methods and properties of the 'base' class for the application.
6181 * Generic Page handler - implement this to start your app..
6184 * MyProject = new Roo.Document({
6186 'load' : true // your events..
6189 'ready' : function() {
6190 // fired on Roo.onReady()
6195 Roo.Document = function(cfg) {
6200 Roo.util.Observable.call(this,cfg);
6204 Roo.onReady(function() {
6205 _this.fireEvent('ready');
6211 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6213 * Ext JS Library 1.1.1
6214 * Copyright(c) 2006-2007, Ext JS, LLC.
6216 * Originally Released Under LGPL - original licence link has changed is not relivant.
6219 * <script type="text/javascript">
6223 * @class Roo.EventManager
6224 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6225 * several useful events directly.
6226 * See {@link Roo.EventObject} for more details on normalized event objects.
6229 Roo.EventManager = function(){
6230 var docReadyEvent, docReadyProcId, docReadyState = false;
6231 var resizeEvent, resizeTask, textEvent, textSize;
6232 var E = Roo.lib.Event;
6233 var D = Roo.lib.Dom;
6238 var fireDocReady = function(){
6240 docReadyState = true;
6243 clearInterval(docReadyProcId);
6245 if(Roo.isGecko || Roo.isOpera) {
6246 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6249 var defer = document.getElementById("ie-deferred-loader");
6251 defer.onreadystatechange = null;
6252 defer.parentNode.removeChild(defer);
6256 docReadyEvent.fire();
6257 docReadyEvent.clearListeners();
6262 var initDocReady = function(){
6263 docReadyEvent = new Roo.util.Event();
6264 if(Roo.isGecko || Roo.isOpera) {
6265 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6267 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6268 var defer = document.getElementById("ie-deferred-loader");
6269 defer.onreadystatechange = function(){
6270 if(this.readyState == "complete"){
6274 }else if(Roo.isSafari){
6275 docReadyProcId = setInterval(function(){
6276 var rs = document.readyState;
6277 if(rs == "complete") {
6282 // no matter what, make sure it fires on load
6283 E.on(window, "load", fireDocReady);
6286 var createBuffered = function(h, o){
6287 var task = new Roo.util.DelayedTask(h);
6289 // create new event object impl so new events don't wipe out properties
6290 e = new Roo.EventObjectImpl(e);
6291 task.delay(o.buffer, h, null, [e]);
6295 var createSingle = function(h, el, ename, fn){
6297 Roo.EventManager.removeListener(el, ename, fn);
6302 var createDelayed = function(h, o){
6304 // create new event object impl so new events don't wipe out properties
6305 e = new Roo.EventObjectImpl(e);
6306 setTimeout(function(){
6311 var transitionEndVal = false;
6313 var transitionEnd = function()
6315 if (transitionEndVal) {
6316 return transitionEndVal;
6318 var el = document.createElement('div');
6320 var transEndEventNames = {
6321 WebkitTransition : 'webkitTransitionEnd',
6322 MozTransition : 'transitionend',
6323 OTransition : 'oTransitionEnd otransitionend',
6324 transition : 'transitionend'
6327 for (var name in transEndEventNames) {
6328 if (el.style[name] !== undefined) {
6329 transitionEndVal = transEndEventNames[name];
6330 return transitionEndVal ;
6337 var listen = function(element, ename, opt, fn, scope)
6339 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6340 fn = fn || o.fn; scope = scope || o.scope;
6341 var el = Roo.getDom(element);
6345 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6348 if (ename == 'transitionend') {
6349 ename = transitionEnd();
6351 var h = function(e){
6352 e = Roo.EventObject.setEvent(e);
6355 t = e.getTarget(o.delegate, el);
6362 if(o.stopEvent === true){
6365 if(o.preventDefault === true){
6368 if(o.stopPropagation === true){
6369 e.stopPropagation();
6372 if(o.normalized === false){
6376 fn.call(scope || el, e, t, o);
6379 h = createDelayed(h, o);
6382 h = createSingle(h, el, ename, fn);
6385 h = createBuffered(h, o);
6388 fn._handlers = fn._handlers || [];
6391 fn._handlers.push([Roo.id(el), ename, h]);
6395 E.on(el, ename, h); // this adds the actuall listener to the object..
6398 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6399 el.addEventListener("DOMMouseScroll", h, false);
6400 E.on(window, 'unload', function(){
6401 el.removeEventListener("DOMMouseScroll", h, false);
6404 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6405 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6410 var stopListening = function(el, ename, fn){
6411 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6413 for(var i = 0, len = hds.length; i < len; i++){
6415 if(h[0] == id && h[1] == ename){
6422 E.un(el, ename, hd);
6423 el = Roo.getDom(el);
6424 if(ename == "mousewheel" && el.addEventListener){
6425 el.removeEventListener("DOMMouseScroll", hd, false);
6427 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6428 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6432 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6439 * @scope Roo.EventManager
6444 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6445 * object with a Roo.EventObject
6446 * @param {Function} fn The method the event invokes
6447 * @param {Object} scope An object that becomes the scope of the handler
6448 * @param {boolean} override If true, the obj passed in becomes
6449 * the execution scope of the listener
6450 * @return {Function} The wrapped function
6453 wrap : function(fn, scope, override){
6455 Roo.EventObject.setEvent(e);
6456 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6461 * Appends an event handler to an element (shorthand for addListener)
6462 * @param {String/HTMLElement} element The html element or id to assign the
6463 * @param {String} eventName The type of event to listen for
6464 * @param {Function} handler The method the event invokes
6465 * @param {Object} scope (optional) The scope in which to execute the handler
6466 * function. The handler function's "this" context.
6467 * @param {Object} options (optional) An object containing handler configuration
6468 * properties. This may contain any of the following properties:<ul>
6469 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6470 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6471 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6472 * <li>preventDefault {Boolean} True to prevent the default action</li>
6473 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6474 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6475 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6476 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6477 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6478 * by the specified number of milliseconds. If the event fires again within that time, the original
6479 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6482 * <b>Combining Options</b><br>
6483 * Using the options argument, it is possible to combine different types of listeners:<br>
6485 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6487 el.on('click', this.onClick, this, {
6494 * <b>Attaching multiple handlers in 1 call</b><br>
6495 * The method also allows for a single argument to be passed which is a config object containing properties
6496 * which specify multiple handlers.
6506 fn: this.onMouseOver
6515 * Or a shorthand syntax:<br>
6518 'click' : this.onClick,
6519 'mouseover' : this.onMouseOver,
6520 'mouseout' : this.onMouseOut
6524 addListener : function(element, eventName, fn, scope, options){
6525 if(typeof eventName == "object"){
6531 if(typeof o[e] == "function"){
6533 listen(element, e, o, o[e], o.scope);
6535 // individual options
6536 listen(element, e, o[e]);
6541 return listen(element, eventName, options, fn, scope);
6545 * Removes an event handler
6547 * @param {String/HTMLElement} element The id or html element to remove the
6549 * @param {String} eventName The type of event
6550 * @param {Function} fn
6551 * @return {Boolean} True if a listener was actually removed
6553 removeListener : function(element, eventName, fn){
6554 return stopListening(element, eventName, fn);
6558 * Fires when the document is ready (before onload and before images are loaded). Can be
6559 * accessed shorthanded Roo.onReady().
6560 * @param {Function} fn The method the event invokes
6561 * @param {Object} scope An object that becomes the scope of the handler
6562 * @param {boolean} options
6564 onDocumentReady : function(fn, scope, options){
6565 if(docReadyState){ // if it already fired
6566 docReadyEvent.addListener(fn, scope, options);
6567 docReadyEvent.fire();
6568 docReadyEvent.clearListeners();
6574 docReadyEvent.addListener(fn, scope, options);
6578 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6579 * @param {Function} fn The method the event invokes
6580 * @param {Object} scope An object that becomes the scope of the handler
6581 * @param {boolean} options
6583 onWindowResize : function(fn, scope, options){
6585 resizeEvent = new Roo.util.Event();
6586 resizeTask = new Roo.util.DelayedTask(function(){
6587 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6589 E.on(window, "resize", function(){
6591 resizeTask.delay(50);
6593 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6597 resizeEvent.addListener(fn, scope, options);
6601 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6602 * @param {Function} fn The method the event invokes
6603 * @param {Object} scope An object that becomes the scope of the handler
6604 * @param {boolean} options
6606 onTextResize : function(fn, scope, options){
6608 textEvent = new Roo.util.Event();
6609 var textEl = new Roo.Element(document.createElement('div'));
6610 textEl.dom.className = 'x-text-resize';
6611 textEl.dom.innerHTML = 'X';
6612 textEl.appendTo(document.body);
6613 textSize = textEl.dom.offsetHeight;
6614 setInterval(function(){
6615 if(textEl.dom.offsetHeight != textSize){
6616 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6618 }, this.textResizeInterval);
6620 textEvent.addListener(fn, scope, options);
6624 * Removes the passed window resize listener.
6625 * @param {Function} fn The method the event invokes
6626 * @param {Object} scope The scope of handler
6628 removeResizeListener : function(fn, scope){
6630 resizeEvent.removeListener(fn, scope);
6635 fireResize : function(){
6637 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6641 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6645 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6647 textResizeInterval : 50
6652 * @scopeAlias pub=Roo.EventManager
6656 * Appends an event handler to an element (shorthand for addListener)
6657 * @param {String/HTMLElement} element The html element or id to assign the
6658 * @param {String} eventName The type of event to listen for
6659 * @param {Function} handler The method the event invokes
6660 * @param {Object} scope (optional) The scope in which to execute the handler
6661 * function. The handler function's "this" context.
6662 * @param {Object} options (optional) An object containing handler configuration
6663 * properties. This may contain any of the following properties:<ul>
6664 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6665 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6666 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6667 * <li>preventDefault {Boolean} True to prevent the default action</li>
6668 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6669 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6670 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6671 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6672 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6673 * by the specified number of milliseconds. If the event fires again within that time, the original
6674 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6677 * <b>Combining Options</b><br>
6678 * Using the options argument, it is possible to combine different types of listeners:<br>
6680 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6682 el.on('click', this.onClick, this, {
6689 * <b>Attaching multiple handlers in 1 call</b><br>
6690 * The method also allows for a single argument to be passed which is a config object containing properties
6691 * which specify multiple handlers.
6701 fn: this.onMouseOver
6710 * Or a shorthand syntax:<br>
6713 'click' : this.onClick,
6714 'mouseover' : this.onMouseOver,
6715 'mouseout' : this.onMouseOut
6719 pub.on = pub.addListener;
6720 pub.un = pub.removeListener;
6722 pub.stoppedMouseDownEvent = new Roo.util.Event();
6726 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6727 * @param {Function} fn The method the event invokes
6728 * @param {Object} scope An object that becomes the scope of the handler
6729 * @param {boolean} override If true, the obj passed in becomes
6730 * the execution scope of the listener
6734 Roo.onReady = Roo.EventManager.onDocumentReady;
6736 Roo.onReady(function(){
6737 var bd = Roo.get(document.body);
6742 : Roo.isIE11 ? "roo-ie11"
6743 : Roo.isEdge ? "roo-edge"
6744 : Roo.isGecko ? "roo-gecko"
6745 : Roo.isOpera ? "roo-opera"
6746 : Roo.isSafari ? "roo-safari" : ""];
6749 cls.push("roo-mac");
6752 cls.push("roo-linux");
6755 cls.push("roo-ios");
6758 cls.push("roo-touch");
6760 if(Roo.isBorderBox){
6761 cls.push('roo-border-box');
6763 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6764 var p = bd.dom.parentNode;
6766 p.className += ' roo-strict';
6769 bd.addClass(cls.join(' '));
6773 * @class Roo.EventObject
6774 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6775 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6778 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6780 var target = e.getTarget();
6783 var myDiv = Roo.get("myDiv");
6784 myDiv.on("click", handleClick);
6786 Roo.EventManager.on("myDiv", 'click', handleClick);
6787 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6791 Roo.EventObject = function(){
6793 var E = Roo.lib.Event;
6795 // safari keypress events for special keys return bad keycodes
6798 63235 : 39, // right
6801 63276 : 33, // page up
6802 63277 : 34, // page down
6803 63272 : 46, // delete
6808 // normalize button clicks
6809 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6810 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6812 Roo.EventObjectImpl = function(e){
6814 this.setEvent(e.browserEvent || e);
6817 Roo.EventObjectImpl.prototype = {
6819 * Used to fix doc tools.
6820 * @scope Roo.EventObject.prototype
6826 /** The normal browser event */
6827 browserEvent : null,
6828 /** The button pressed in a mouse event */
6830 /** True if the shift key was down during the event */
6832 /** True if the control key was down during the event */
6834 /** True if the alt key was down during the event */
6893 setEvent : function(e){
6894 if(e == this || (e && e.browserEvent)){ // already wrapped
6897 this.browserEvent = e;
6899 // normalize buttons
6900 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6901 if(e.type == 'click' && this.button == -1){
6905 this.shiftKey = e.shiftKey;
6906 // mac metaKey behaves like ctrlKey
6907 this.ctrlKey = e.ctrlKey || e.metaKey;
6908 this.altKey = e.altKey;
6909 // in getKey these will be normalized for the mac
6910 this.keyCode = e.keyCode;
6911 // keyup warnings on firefox.
6912 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6913 // cache the target for the delayed and or buffered events
6914 this.target = E.getTarget(e);
6916 this.xy = E.getXY(e);
6919 this.shiftKey = false;
6920 this.ctrlKey = false;
6921 this.altKey = false;
6931 * Stop the event (preventDefault and stopPropagation)
6933 stopEvent : function(){
6934 if(this.browserEvent){
6935 if(this.browserEvent.type == 'mousedown'){
6936 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6938 E.stopEvent(this.browserEvent);
6943 * Prevents the browsers default handling of the event.
6945 preventDefault : function(){
6946 if(this.browserEvent){
6947 E.preventDefault(this.browserEvent);
6952 isNavKeyPress : function(){
6953 var k = this.keyCode;
6954 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6955 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6958 isSpecialKey : function(){
6959 var k = this.keyCode;
6960 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6961 (k == 16) || (k == 17) ||
6962 (k >= 18 && k <= 20) ||
6963 (k >= 33 && k <= 35) ||
6964 (k >= 36 && k <= 39) ||
6965 (k >= 44 && k <= 45);
6968 * Cancels bubbling of the event.
6970 stopPropagation : function(){
6971 if(this.browserEvent){
6972 if(this.type == 'mousedown'){
6973 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6975 E.stopPropagation(this.browserEvent);
6980 * Gets the key code for the event.
6983 getCharCode : function(){
6984 return this.charCode || this.keyCode;
6988 * Returns a normalized keyCode for the event.
6989 * @return {Number} The key code
6991 getKey : function(){
6992 var k = this.keyCode || this.charCode;
6993 return Roo.isSafari ? (safariKeys[k] || k) : k;
6997 * Gets the x coordinate of the event.
7000 getPageX : function(){
7005 * Gets the y coordinate of the event.
7008 getPageY : function(){
7013 * Gets the time of the event.
7016 getTime : function(){
7017 if(this.browserEvent){
7018 return E.getTime(this.browserEvent);
7024 * Gets the page coordinates of the event.
7025 * @return {Array} The xy values like [x, y]
7032 * Gets the target for the event.
7033 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7034 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7035 search as a number or element (defaults to 10 || document.body)
7036 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7037 * @return {HTMLelement}
7039 getTarget : function(selector, maxDepth, returnEl){
7040 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7043 * Gets the related target.
7044 * @return {HTMLElement}
7046 getRelatedTarget : function(){
7047 if(this.browserEvent){
7048 return E.getRelatedTarget(this.browserEvent);
7054 * Normalizes mouse wheel delta across browsers
7055 * @return {Number} The delta
7057 getWheelDelta : function(){
7058 var e = this.browserEvent;
7060 if(e.wheelDelta){ /* IE/Opera. */
7061 delta = e.wheelDelta/120;
7062 }else if(e.detail){ /* Mozilla case. */
7063 delta = -e.detail/3;
7069 * Returns true if the control, meta, shift or alt key was pressed during this event.
7072 hasModifier : function(){
7073 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7077 * Returns true if the target of this event equals el or is a child of el
7078 * @param {String/HTMLElement/Element} el
7079 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7082 within : function(el, related){
7083 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7084 return t && Roo.fly(el).contains(t);
7087 getPoint : function(){
7088 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7092 return new Roo.EventObjectImpl();
7097 * Ext JS Library 1.1.1
7098 * Copyright(c) 2006-2007, Ext JS, LLC.
7100 * Originally Released Under LGPL - original licence link has changed is not relivant.
7103 * <script type="text/javascript">
7107 // was in Composite Element!??!?!
7110 var D = Roo.lib.Dom;
7111 var E = Roo.lib.Event;
7112 var A = Roo.lib.Anim;
7114 // local style camelizing for speed
7116 var camelRe = /(-[a-z])/gi;
7117 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7118 var view = document.defaultView;
7121 * @class Roo.Element
7122 * Represents an Element in the DOM.<br><br>
7125 var el = Roo.get("my-div");
7128 var el = getEl("my-div");
7130 // or with a DOM element
7131 var el = Roo.get(myDivElement);
7133 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7134 * each call instead of constructing a new one.<br><br>
7135 * <b>Animations</b><br />
7136 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7137 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7139 Option Default Description
7140 --------- -------- ---------------------------------------------
7141 duration .35 The duration of the animation in seconds
7142 easing easeOut The YUI easing method
7143 callback none A function to execute when the anim completes
7144 scope this The scope (this) of the callback function
7146 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7147 * manipulate the animation. Here's an example:
7149 var el = Roo.get("my-div");
7154 // default animation
7155 el.setWidth(100, true);
7157 // animation with some options set
7164 // using the "anim" property to get the Anim object
7170 el.setWidth(100, opt);
7172 if(opt.anim.isAnimated()){
7176 * <b> Composite (Collections of) Elements</b><br />
7177 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7178 * @constructor Create a new Element directly.
7179 * @param {String/HTMLElement} element
7180 * @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).
7182 Roo.Element = function(element, forceNew)
7184 var dom = typeof element == "string" ?
7185 document.getElementById(element) : element;
7187 this.listeners = {};
7189 if(!dom){ // invalid id/element
7193 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7194 return Roo.Element.cache[id];
7204 * The DOM element ID
7207 this.id = id || Roo.id(dom);
7209 return this; // assumed for cctor?
7212 var El = Roo.Element;
7216 * The element's default display mode (defaults to "")
7219 originalDisplay : "",
7222 // note this is overridden in BS version..
7225 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7231 * Sets the element's visibility mode. When setVisible() is called it
7232 * will use this to determine whether to set the visibility or the display property.
7233 * @param visMode Element.VISIBILITY or Element.DISPLAY
7234 * @return {Roo.Element} this
7236 setVisibilityMode : function(visMode){
7237 this.visibilityMode = visMode;
7241 * Convenience method for setVisibilityMode(Element.DISPLAY)
7242 * @param {String} display (optional) What to set display to when visible
7243 * @return {Roo.Element} this
7245 enableDisplayMode : function(display){
7246 this.setVisibilityMode(El.DISPLAY);
7247 if(typeof display != "undefined") { this.originalDisplay = display; }
7252 * 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)
7253 * @param {String} selector The simple selector to test
7254 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7255 search as a number or element (defaults to 10 || document.body)
7256 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7257 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7259 findParent : function(simpleSelector, maxDepth, returnEl){
7260 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7261 maxDepth = maxDepth || 50;
7262 if(typeof maxDepth != "number"){
7263 stopEl = Roo.getDom(maxDepth);
7266 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7267 if(dq.is(p, simpleSelector)){
7268 return returnEl ? Roo.get(p) : p;
7278 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7279 * @param {String} selector The simple selector to test
7280 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7281 search as a number or element (defaults to 10 || document.body)
7282 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7283 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7285 findParentNode : function(simpleSelector, maxDepth, returnEl){
7286 var p = Roo.fly(this.dom.parentNode, '_internal');
7287 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7291 * Looks at the scrollable parent element
7293 findScrollableParent : function()
7295 var overflowRegex = /(auto|scroll)/;
7297 if(this.getStyle('position') === 'fixed'){
7298 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7301 var excludeStaticParent = this.getStyle('position') === "absolute";
7303 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7305 if (excludeStaticParent && parent.getStyle('position') === "static") {
7309 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7313 if(parent.dom.nodeName.toLowerCase() == 'body'){
7314 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7318 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7322 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7323 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7324 * @param {String} selector The simple selector to test
7325 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7326 search as a number or element (defaults to 10 || document.body)
7327 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7329 up : function(simpleSelector, maxDepth){
7330 return this.findParentNode(simpleSelector, maxDepth, true);
7336 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7337 * @param {String} selector The simple selector to test
7338 * @return {Boolean} True if this element matches the selector, else false
7340 is : function(simpleSelector){
7341 return Roo.DomQuery.is(this.dom, simpleSelector);
7345 * Perform animation on this element.
7346 * @param {Object} args The YUI animation control args
7347 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7348 * @param {Function} onComplete (optional) Function to call when animation completes
7349 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7350 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7351 * @return {Roo.Element} this
7353 animate : function(args, duration, onComplete, easing, animType){
7354 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7359 * @private Internal animation call
7361 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7362 animType = animType || 'run';
7364 var anim = Roo.lib.Anim[animType](
7366 (opt.duration || defaultDur) || .35,
7367 (opt.easing || defaultEase) || 'easeOut',
7369 Roo.callback(cb, this);
7370 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7378 // private legacy anim prep
7379 preanim : function(a, i){
7380 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7384 * Removes worthless text nodes
7385 * @param {Boolean} forceReclean (optional) By default the element
7386 * keeps track if it has been cleaned already so
7387 * you can call this over and over. However, if you update the element and
7388 * need to force a reclean, you can pass true.
7390 clean : function(forceReclean){
7391 if(this.isCleaned && forceReclean !== true){
7395 var d = this.dom, n = d.firstChild, ni = -1;
7397 var nx = n.nextSibling;
7398 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7405 this.isCleaned = true;
7410 calcOffsetsTo : function(el){
7413 var restorePos = false;
7414 if(el.getStyle('position') == 'static'){
7415 el.position('relative');
7420 while(op && op != d && op.tagName != 'HTML'){
7423 op = op.offsetParent;
7426 el.position('static');
7432 * Scrolls this element into view within the passed container.
7433 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7434 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7435 * @return {Roo.Element} this
7437 scrollIntoView : function(container, hscroll){
7438 var c = Roo.getDom(container) || document.body;
7441 var o = this.calcOffsetsTo(c),
7444 b = t+el.offsetHeight,
7445 r = l+el.offsetWidth;
7447 var ch = c.clientHeight;
7448 var ct = parseInt(c.scrollTop, 10);
7449 var cl = parseInt(c.scrollLeft, 10);
7451 var cr = cl + c.clientWidth;
7459 if(hscroll !== false){
7463 c.scrollLeft = r-c.clientWidth;
7470 scrollChildIntoView : function(child, hscroll){
7471 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7475 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7476 * the new height may not be available immediately.
7477 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7478 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7479 * @param {Function} onComplete (optional) Function to call when animation completes
7480 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7481 * @return {Roo.Element} this
7483 autoHeight : function(animate, duration, onComplete, easing){
7484 var oldHeight = this.getHeight();
7486 this.setHeight(1); // force clipping
7487 setTimeout(function(){
7488 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7490 this.setHeight(height);
7492 if(typeof onComplete == "function"){
7496 this.setHeight(oldHeight); // restore original height
7497 this.setHeight(height, animate, duration, function(){
7499 if(typeof onComplete == "function") { onComplete(); }
7500 }.createDelegate(this), easing);
7502 }.createDelegate(this), 0);
7507 * Returns true if this element is an ancestor of the passed element
7508 * @param {HTMLElement/String} el The element to check
7509 * @return {Boolean} True if this element is an ancestor of el, else false
7511 contains : function(el){
7512 if(!el){return false;}
7513 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7517 * Checks whether the element is currently visible using both visibility and display properties.
7518 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7519 * @return {Boolean} True if the element is currently visible, else false
7521 isVisible : function(deep) {
7522 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7523 if(deep !== true || !vis){
7526 var p = this.dom.parentNode;
7527 while(p && p.tagName.toLowerCase() != "body"){
7528 if(!Roo.fly(p, '_isVisible').isVisible()){
7537 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7538 * @param {String} selector The CSS selector
7539 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7540 * @return {CompositeElement/CompositeElementLite} The composite element
7542 select : function(selector, unique){
7543 return El.select(selector, unique, this.dom);
7547 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7548 * @param {String} selector The CSS selector
7549 * @return {Array} An array of the matched nodes
7551 query : function(selector, unique){
7552 return Roo.DomQuery.select(selector, this.dom);
7556 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7557 * @param {String} selector The CSS selector
7558 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7559 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7561 child : function(selector, returnDom){
7562 var n = Roo.DomQuery.selectNode(selector, this.dom);
7563 return returnDom ? n : Roo.get(n);
7567 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7568 * @param {String} selector The CSS selector
7569 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7570 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7572 down : function(selector, returnDom){
7573 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7574 return returnDom ? n : Roo.get(n);
7578 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7579 * @param {String} group The group the DD object is member of
7580 * @param {Object} config The DD config object
7581 * @param {Object} overrides An object containing methods to override/implement on the DD object
7582 * @return {Roo.dd.DD} The DD object
7584 initDD : function(group, config, overrides){
7585 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7586 return Roo.apply(dd, overrides);
7590 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7591 * @param {String} group The group the DDProxy object is member of
7592 * @param {Object} config The DDProxy config object
7593 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7594 * @return {Roo.dd.DDProxy} The DDProxy object
7596 initDDProxy : function(group, config, overrides){
7597 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7598 return Roo.apply(dd, overrides);
7602 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7603 * @param {String} group The group the DDTarget object is member of
7604 * @param {Object} config The DDTarget config object
7605 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7606 * @return {Roo.dd.DDTarget} The DDTarget object
7608 initDDTarget : function(group, config, overrides){
7609 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7610 return Roo.apply(dd, overrides);
7614 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7615 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7616 * @param {Boolean} visible Whether the element is visible
7617 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7618 * @return {Roo.Element} this
7620 setVisible : function(visible, animate){
7622 if(this.visibilityMode == El.DISPLAY){
7623 this.setDisplayed(visible);
7626 this.dom.style.visibility = visible ? "visible" : "hidden";
7629 // closure for composites
7631 var visMode = this.visibilityMode;
7633 this.setOpacity(.01);
7634 this.setVisible(true);
7636 this.anim({opacity: { to: (visible?1:0) }},
7637 this.preanim(arguments, 1),
7638 null, .35, 'easeIn', function(){
7640 if(visMode == El.DISPLAY){
7641 dom.style.display = "none";
7643 dom.style.visibility = "hidden";
7645 Roo.get(dom).setOpacity(1);
7653 * Returns true if display is not "none"
7656 isDisplayed : function() {
7657 return this.getStyle("display") != "none";
7661 * Toggles the element's visibility or display, depending on visibility mode.
7662 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7663 * @return {Roo.Element} this
7665 toggle : function(animate){
7666 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7671 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7672 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7673 * @return {Roo.Element} this
7675 setDisplayed : function(value) {
7676 if(typeof value == "boolean"){
7677 value = value ? this.originalDisplay : "none";
7679 this.setStyle("display", value);
7684 * Tries to focus the element. Any exceptions are caught and ignored.
7685 * @return {Roo.Element} this
7687 focus : function() {
7695 * Tries to blur the element. Any exceptions are caught and ignored.
7696 * @return {Roo.Element} this
7706 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7707 * @param {String/Array} className The CSS class to add, or an array of classes
7708 * @return {Roo.Element} this
7710 addClass : function(className){
7711 if(className instanceof Array){
7712 for(var i = 0, len = className.length; i < len; i++) {
7713 this.addClass(className[i]);
7716 if(className && !this.hasClass(className)){
7717 if (this.dom instanceof SVGElement) {
7718 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
7720 this.dom.className = this.dom.className + " " + className;
7728 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7729 * @param {String/Array} className The CSS class to add, or an array of classes
7730 * @return {Roo.Element} this
7732 radioClass : function(className){
7733 var siblings = this.dom.parentNode.childNodes;
7734 for(var i = 0; i < siblings.length; i++) {
7735 var s = siblings[i];
7736 if(s.nodeType == 1){
7737 Roo.get(s).removeClass(className);
7740 this.addClass(className);
7745 * Removes one or more CSS classes from the element.
7746 * @param {String/Array} className The CSS class to remove, or an array of classes
7747 * @return {Roo.Element} this
7749 removeClass : function(className){
7751 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
7752 if(!className || !cn){
7755 if(className instanceof Array){
7756 for(var i = 0, len = className.length; i < len; i++) {
7757 this.removeClass(className[i]);
7760 if(this.hasClass(className)){
7761 var re = this.classReCache[className];
7763 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7764 this.classReCache[className] = re;
7766 if (this.dom instanceof SVGElement) {
7767 this.dom.className.baseVal = cn.replace(re, " ");
7769 this.dom.className = cn.replace(re, " ");
7780 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7781 * @param {String} className The CSS class to toggle
7782 * @return {Roo.Element} this
7784 toggleClass : function(className){
7785 if(this.hasClass(className)){
7786 this.removeClass(className);
7788 this.addClass(className);
7794 * Checks if the specified CSS class exists on this element's DOM node.
7795 * @param {String} className The CSS class to check for
7796 * @return {Boolean} True if the class exists, else false
7798 hasClass : function(className){
7799 if (this.dom instanceof SVGElement) {
7800 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
7802 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7806 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7807 * @param {String} oldClassName The CSS class to replace
7808 * @param {String} newClassName The replacement CSS class
7809 * @return {Roo.Element} this
7811 replaceClass : function(oldClassName, newClassName){
7812 this.removeClass(oldClassName);
7813 this.addClass(newClassName);
7818 * Returns an object with properties matching the styles requested.
7819 * For example, el.getStyles('color', 'font-size', 'width') might return
7820 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7821 * @param {String} style1 A style name
7822 * @param {String} style2 A style name
7823 * @param {String} etc.
7824 * @return {Object} The style object
7826 getStyles : function(){
7827 var a = arguments, len = a.length, r = {};
7828 for(var i = 0; i < len; i++){
7829 r[a[i]] = this.getStyle(a[i]);
7835 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7836 * @param {String} property The style property whose value is returned.
7837 * @return {String} The current value of the style property for this element.
7839 getStyle : function(){
7840 return view && view.getComputedStyle ?
7842 var el = this.dom, v, cs, camel;
7843 if(prop == 'float'){
7846 if(el.style && (v = el.style[prop])){
7849 if(cs = view.getComputedStyle(el, "")){
7850 if(!(camel = propCache[prop])){
7851 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7858 var el = this.dom, v, cs, camel;
7859 if(prop == 'opacity'){
7860 if(typeof el.style.filter == 'string'){
7861 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7863 var fv = parseFloat(m[1]);
7865 return fv ? fv / 100 : 0;
7870 }else if(prop == 'float'){
7871 prop = "styleFloat";
7873 if(!(camel = propCache[prop])){
7874 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7876 if(v = el.style[camel]){
7879 if(cs = el.currentStyle){
7887 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7888 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7889 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7890 * @return {Roo.Element} this
7892 setStyle : function(prop, value){
7893 if(typeof prop == "string"){
7895 if (prop == 'float') {
7896 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7901 if(!(camel = propCache[prop])){
7902 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7905 if(camel == 'opacity') {
7906 this.setOpacity(value);
7908 this.dom.style[camel] = value;
7911 for(var style in prop){
7912 if(typeof prop[style] != "function"){
7913 this.setStyle(style, prop[style]);
7921 * More flexible version of {@link #setStyle} for setting style properties.
7922 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7923 * a function which returns such a specification.
7924 * @return {Roo.Element} this
7926 applyStyles : function(style){
7927 Roo.DomHelper.applyStyles(this.dom, style);
7932 * 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).
7933 * @return {Number} The X position of the element
7936 return D.getX(this.dom);
7940 * 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).
7941 * @return {Number} The Y position of the element
7944 return D.getY(this.dom);
7948 * 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).
7949 * @return {Array} The XY position of the element
7952 return D.getXY(this.dom);
7956 * 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).
7957 * @param {Number} The X position of the element
7958 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7959 * @return {Roo.Element} this
7961 setX : function(x, animate){
7963 D.setX(this.dom, x);
7965 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7971 * 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).
7972 * @param {Number} The Y position of the element
7973 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7974 * @return {Roo.Element} this
7976 setY : function(y, animate){
7978 D.setY(this.dom, y);
7980 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7986 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7987 * @param {String} left The left CSS property value
7988 * @return {Roo.Element} this
7990 setLeft : function(left){
7991 this.setStyle("left", this.addUnits(left));
7996 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7997 * @param {String} top The top CSS property value
7998 * @return {Roo.Element} this
8000 setTop : function(top){
8001 this.setStyle("top", this.addUnits(top));
8006 * Sets the element's CSS right style.
8007 * @param {String} right The right CSS property value
8008 * @return {Roo.Element} this
8010 setRight : function(right){
8011 this.setStyle("right", this.addUnits(right));
8016 * Sets the element's CSS bottom style.
8017 * @param {String} bottom The bottom CSS property value
8018 * @return {Roo.Element} this
8020 setBottom : function(bottom){
8021 this.setStyle("bottom", this.addUnits(bottom));
8026 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8027 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8028 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8029 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 setXY : function(pos, animate){
8034 D.setXY(this.dom, pos);
8036 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8042 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8043 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8044 * @param {Number} x X value for new position (coordinates are page-based)
8045 * @param {Number} y Y value for new position (coordinates are page-based)
8046 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8047 * @return {Roo.Element} this
8049 setLocation : function(x, y, animate){
8050 this.setXY([x, y], this.preanim(arguments, 2));
8055 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8056 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8057 * @param {Number} x X value for new position (coordinates are page-based)
8058 * @param {Number} y Y value for new position (coordinates are page-based)
8059 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8060 * @return {Roo.Element} this
8062 moveTo : function(x, y, animate){
8063 this.setXY([x, y], this.preanim(arguments, 2));
8068 * Returns the region of the given element.
8069 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8070 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8072 getRegion : function(){
8073 return D.getRegion(this.dom);
8077 * Returns the offset height of the element
8078 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8079 * @return {Number} The element's height
8081 getHeight : function(contentHeight){
8082 var h = this.dom.offsetHeight || 0;
8083 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8087 * Returns the offset width of the element
8088 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8089 * @return {Number} The element's width
8091 getWidth : function(contentWidth){
8092 var w = this.dom.offsetWidth || 0;
8093 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8097 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8098 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8099 * if a height has not been set using CSS.
8102 getComputedHeight : function(){
8103 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8105 h = parseInt(this.getStyle('height'), 10) || 0;
8106 if(!this.isBorderBox()){
8107 h += this.getFrameWidth('tb');
8114 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8115 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8116 * if a width has not been set using CSS.
8119 getComputedWidth : function(){
8120 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8122 w = parseInt(this.getStyle('width'), 10) || 0;
8123 if(!this.isBorderBox()){
8124 w += this.getFrameWidth('lr');
8131 * Returns the size of the element.
8132 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8133 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8135 getSize : function(contentSize){
8136 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8140 * Returns the width and height of the viewport.
8141 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8143 getViewSize : function(){
8144 var d = this.dom, doc = document, aw = 0, ah = 0;
8145 if(d == doc || d == doc.body){
8146 return {width : D.getViewWidth(), height: D.getViewHeight()};
8149 width : d.clientWidth,
8150 height: d.clientHeight
8156 * Returns the value of the "value" attribute
8157 * @param {Boolean} asNumber true to parse the value as a number
8158 * @return {String/Number}
8160 getValue : function(asNumber){
8161 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8165 adjustWidth : function(width){
8166 if(typeof width == "number"){
8167 if(this.autoBoxAdjust && !this.isBorderBox()){
8168 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8178 adjustHeight : function(height){
8179 if(typeof height == "number"){
8180 if(this.autoBoxAdjust && !this.isBorderBox()){
8181 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8191 * Set the width of the element
8192 * @param {Number} width The new width
8193 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8194 * @return {Roo.Element} this
8196 setWidth : function(width, animate){
8197 width = this.adjustWidth(width);
8199 this.dom.style.width = this.addUnits(width);
8201 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8207 * Set the height of the element
8208 * @param {Number} height The new height
8209 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8210 * @return {Roo.Element} this
8212 setHeight : function(height, animate){
8213 height = this.adjustHeight(height);
8215 this.dom.style.height = this.addUnits(height);
8217 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8223 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8224 * @param {Number} width The new width
8225 * @param {Number} height The new height
8226 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8227 * @return {Roo.Element} this
8229 setSize : function(width, height, animate){
8230 if(typeof width == "object"){ // in case of object from getSize()
8231 height = width.height; width = width.width;
8233 width = this.adjustWidth(width); height = this.adjustHeight(height);
8235 this.dom.style.width = this.addUnits(width);
8236 this.dom.style.height = this.addUnits(height);
8238 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8244 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8245 * @param {Number} x X value for new position (coordinates are page-based)
8246 * @param {Number} y Y value for new position (coordinates are page-based)
8247 * @param {Number} width The new width
8248 * @param {Number} height The new height
8249 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8250 * @return {Roo.Element} this
8252 setBounds : function(x, y, width, height, animate){
8254 this.setSize(width, height);
8255 this.setLocation(x, y);
8257 width = this.adjustWidth(width); height = this.adjustHeight(height);
8258 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8259 this.preanim(arguments, 4), 'motion');
8265 * 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.
8266 * @param {Roo.lib.Region} region The region to fill
8267 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8268 * @return {Roo.Element} this
8270 setRegion : function(region, animate){
8271 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8276 * Appends an event handler
8278 * @param {String} eventName The type of event to append
8279 * @param {Function} fn The method the event invokes
8280 * @param {Object} scope (optional) The scope (this object) of the fn
8281 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8283 addListener : function(eventName, fn, scope, options)
8285 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
8286 this.addListener('touchstart', this.onTapHandler, this);
8289 // we need to handle a special case where dom element is a svg element.
8290 // in this case we do not actua
8295 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
8296 if (typeof(this.listeners[eventName]) == 'undefined') {
8297 this.listeners[eventName] = new Roo.util.Event(this, eventName);
8299 this.listeners[eventName].addListener(fn, scope, options);
8304 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8309 onTapHandler : function(event)
8311 if(!this.tapedTwice) {
8312 this.tapedTwice = true;
8314 setTimeout( function() {
8315 s.tapedTwice = false;
8319 event.preventDefault();
8320 var revent = new MouseEvent('dblclick', {
8326 this.dom.dispatchEvent(revent);
8327 //action on double tap goes below
8332 * Removes an event handler from this element
8333 * @param {String} eventName the type of event to remove
8334 * @param {Function} fn the method the event invokes
8335 * @param {Function} scope (needed for svg fake listeners)
8336 * @return {Roo.Element} this
8338 removeListener : function(eventName, fn, scope){
8339 Roo.EventManager.removeListener(this.dom, eventName, fn);
8340 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
8343 this.listeners[eventName].removeListener(fn, scope);
8348 * Removes all previous added listeners from this element
8349 * @return {Roo.Element} this
8351 removeAllListeners : function(){
8352 E.purgeElement(this.dom);
8353 this.listeners = {};
8357 relayEvent : function(eventName, observable){
8358 this.on(eventName, function(e){
8359 observable.fireEvent(eventName, e);
8365 * Set the opacity of the element
8366 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8367 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8368 * @return {Roo.Element} this
8370 setOpacity : function(opacity, animate){
8372 var s = this.dom.style;
8375 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8376 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8378 s.opacity = opacity;
8381 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8387 * Gets the left X coordinate
8388 * @param {Boolean} local True to get the local css position instead of page coordinate
8391 getLeft : function(local){
8395 return parseInt(this.getStyle("left"), 10) || 0;
8400 * Gets the right X coordinate of the element (element X position + element width)
8401 * @param {Boolean} local True to get the local css position instead of page coordinate
8404 getRight : function(local){
8406 return this.getX() + this.getWidth();
8408 return (this.getLeft(true) + this.getWidth()) || 0;
8413 * Gets the top Y coordinate
8414 * @param {Boolean} local True to get the local css position instead of page coordinate
8417 getTop : function(local) {
8421 return parseInt(this.getStyle("top"), 10) || 0;
8426 * Gets the bottom Y coordinate of the element (element Y position + element height)
8427 * @param {Boolean} local True to get the local css position instead of page coordinate
8430 getBottom : function(local){
8432 return this.getY() + this.getHeight();
8434 return (this.getTop(true) + this.getHeight()) || 0;
8439 * Initializes positioning on this element. If a desired position is not passed, it will make the
8440 * the element positioned relative IF it is not already positioned.
8441 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8442 * @param {Number} zIndex (optional) The zIndex to apply
8443 * @param {Number} x (optional) Set the page X position
8444 * @param {Number} y (optional) Set the page Y position
8446 position : function(pos, zIndex, x, y){
8448 if(this.getStyle('position') == 'static'){
8449 this.setStyle('position', 'relative');
8452 this.setStyle("position", pos);
8455 this.setStyle("z-index", zIndex);
8457 if(x !== undefined && y !== undefined){
8459 }else if(x !== undefined){
8461 }else if(y !== undefined){
8467 * Clear positioning back to the default when the document was loaded
8468 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8469 * @return {Roo.Element} this
8471 clearPositioning : function(value){
8479 "position" : "static"
8485 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8486 * snapshot before performing an update and then restoring the element.
8489 getPositioning : function(){
8490 var l = this.getStyle("left");
8491 var t = this.getStyle("top");
8493 "position" : this.getStyle("position"),
8495 "right" : l ? "" : this.getStyle("right"),
8497 "bottom" : t ? "" : this.getStyle("bottom"),
8498 "z-index" : this.getStyle("z-index")
8503 * Gets the width of the border(s) for the specified side(s)
8504 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8505 * passing lr would get the border (l)eft width + the border (r)ight width.
8506 * @return {Number} The width of the sides passed added together
8508 getBorderWidth : function(side){
8509 return this.addStyles(side, El.borders);
8513 * Gets the width of the padding(s) for the specified side(s)
8514 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8515 * passing lr would get the padding (l)eft + the padding (r)ight.
8516 * @return {Number} The padding of the sides passed added together
8518 getPadding : function(side){
8519 return this.addStyles(side, El.paddings);
8523 * Set positioning with an object returned by getPositioning().
8524 * @param {Object} posCfg
8525 * @return {Roo.Element} this
8527 setPositioning : function(pc){
8528 this.applyStyles(pc);
8529 if(pc.right == "auto"){
8530 this.dom.style.right = "";
8532 if(pc.bottom == "auto"){
8533 this.dom.style.bottom = "";
8539 fixDisplay : function(){
8540 if(this.getStyle("display") == "none"){
8541 this.setStyle("visibility", "hidden");
8542 this.setStyle("display", this.originalDisplay); // first try reverting to default
8543 if(this.getStyle("display") == "none"){ // if that fails, default to block
8544 this.setStyle("display", "block");
8550 * Quick set left and top adding default units
8551 * @param {String} left The left CSS property value
8552 * @param {String} top The top CSS property value
8553 * @return {Roo.Element} this
8555 setLeftTop : function(left, top){
8556 this.dom.style.left = this.addUnits(left);
8557 this.dom.style.top = this.addUnits(top);
8562 * Move this element relative to its current position.
8563 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8564 * @param {Number} distance How far to move the element in pixels
8565 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8566 * @return {Roo.Element} this
8568 move : function(direction, distance, animate){
8569 var xy = this.getXY();
8570 direction = direction.toLowerCase();
8574 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8578 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8583 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8588 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8595 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8596 * @return {Roo.Element} this
8599 if(!this.isClipped){
8600 this.isClipped = true;
8601 this.originalClip = {
8602 "o": this.getStyle("overflow"),
8603 "x": this.getStyle("overflow-x"),
8604 "y": this.getStyle("overflow-y")
8606 this.setStyle("overflow", "hidden");
8607 this.setStyle("overflow-x", "hidden");
8608 this.setStyle("overflow-y", "hidden");
8614 * Return clipping (overflow) to original clipping before clip() was called
8615 * @return {Roo.Element} this
8617 unclip : function(){
8619 this.isClipped = false;
8620 var o = this.originalClip;
8621 if(o.o){this.setStyle("overflow", o.o);}
8622 if(o.x){this.setStyle("overflow-x", o.x);}
8623 if(o.y){this.setStyle("overflow-y", o.y);}
8630 * Gets the x,y coordinates specified by the anchor position on the element.
8631 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8632 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8633 * {width: (target width), height: (target height)} (defaults to the element's current size)
8634 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8635 * @return {Array} [x, y] An array containing the element's x and y coordinates
8637 getAnchorXY : function(anchor, local, s){
8638 //Passing a different size is useful for pre-calculating anchors,
8639 //especially for anchored animations that change the el size.
8641 var w, h, vp = false;
8644 if(d == document.body || d == document){
8646 w = D.getViewWidth(); h = D.getViewHeight();
8648 w = this.getWidth(); h = this.getHeight();
8651 w = s.width; h = s.height;
8653 var x = 0, y = 0, r = Math.round;
8654 switch((anchor || "tl").toLowerCase()){
8696 var sc = this.getScroll();
8697 return [x + sc.left, y + sc.top];
8699 //Add the element's offset xy
8700 var o = this.getXY();
8701 return [x+o[0], y+o[1]];
8705 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8706 * supported position values.
8707 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8708 * @param {String} position The position to align to.
8709 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8710 * @return {Array} [x, y]
8712 getAlignToXY : function(el, p, o)
8717 throw "Element.alignTo with an element that doesn't exist";
8719 var c = false; //constrain to viewport
8720 var p1 = "", p2 = "";
8727 }else if(p.indexOf("-") == -1){
8730 p = p.toLowerCase();
8731 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8733 throw "Element.alignTo with an invalid alignment " + p;
8735 p1 = m[1]; p2 = m[2]; c = !!m[3];
8737 //Subtract the aligned el's internal xy from the target's offset xy
8738 //plus custom offset to get the aligned el's new offset xy
8739 var a1 = this.getAnchorXY(p1, true);
8740 var a2 = el.getAnchorXY(p2, false);
8741 var x = a2[0] - a1[0] + o[0];
8742 var y = a2[1] - a1[1] + o[1];
8744 //constrain the aligned el to viewport if necessary
8745 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8746 // 5px of margin for ie
8747 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8749 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8750 //perpendicular to the vp border, allow the aligned el to slide on that border,
8751 //otherwise swap the aligned el to the opposite border of the target.
8752 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8753 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8754 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8755 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8758 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8759 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8761 if((x+w) > dw + scrollX){
8762 x = swapX ? r.left-w : dw+scrollX-w;
8765 x = swapX ? r.right : scrollX;
8767 if((y+h) > dh + scrollY){
8768 y = swapY ? r.top-h : dh+scrollY-h;
8771 y = swapY ? r.bottom : scrollY;
8778 getConstrainToXY : function(){
8779 var os = {top:0, left:0, bottom:0, right: 0};
8781 return function(el, local, offsets, proposedXY){
8783 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8785 var vw, vh, vx = 0, vy = 0;
8786 if(el.dom == document.body || el.dom == document){
8787 vw = Roo.lib.Dom.getViewWidth();
8788 vh = Roo.lib.Dom.getViewHeight();
8790 vw = el.dom.clientWidth;
8791 vh = el.dom.clientHeight;
8793 var vxy = el.getXY();
8799 var s = el.getScroll();
8801 vx += offsets.left + s.left;
8802 vy += offsets.top + s.top;
8804 vw -= offsets.right;
8805 vh -= offsets.bottom;
8810 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8811 var x = xy[0], y = xy[1];
8812 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8814 // only move it if it needs it
8817 // first validate right/bottom
8826 // then make sure top/left isn't negative
8835 return moved ? [x, y] : false;
8840 adjustForConstraints : function(xy, parent, offsets){
8841 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8845 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8846 * document it aligns it to the viewport.
8847 * The position parameter is optional, and can be specified in any one of the following formats:
8849 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8850 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8851 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8852 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8853 * <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
8854 * element's anchor point, and the second value is used as the target's anchor point.</li>
8856 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8857 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8858 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8859 * that specified in order to enforce the viewport constraints.
8860 * Following are all of the supported anchor positions:
8863 ----- -----------------------------
8864 tl The top left corner (default)
8865 t The center of the top edge
8866 tr The top right corner
8867 l The center of the left edge
8868 c In the center of the element
8869 r The center of the right edge
8870 bl The bottom left corner
8871 b The center of the bottom edge
8872 br The bottom right corner
8876 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8877 el.alignTo("other-el");
8879 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8880 el.alignTo("other-el", "tr?");
8882 // align the bottom right corner of el with the center left edge of other-el
8883 el.alignTo("other-el", "br-l?");
8885 // align the center of el with the bottom left corner of other-el and
8886 // adjust the x position by -6 pixels (and the y position by 0)
8887 el.alignTo("other-el", "c-bl", [-6, 0]);
8889 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8890 * @param {String} position The position to align to.
8891 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8892 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8893 * @return {Roo.Element} this
8895 alignTo : function(element, position, offsets, animate){
8896 var xy = this.getAlignToXY(element, position, offsets);
8897 this.setXY(xy, this.preanim(arguments, 3));
8902 * Anchors an element to another element and realigns it when the window is resized.
8903 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8904 * @param {String} position The position to align to.
8905 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8906 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8907 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8908 * is a number, it is used as the buffer delay (defaults to 50ms).
8909 * @param {Function} callback The function to call after the animation finishes
8910 * @return {Roo.Element} this
8912 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8913 var action = function(){
8914 this.alignTo(el, alignment, offsets, animate);
8915 Roo.callback(callback, this);
8917 Roo.EventManager.onWindowResize(action, this);
8918 var tm = typeof monitorScroll;
8919 if(tm != 'undefined'){
8920 Roo.EventManager.on(window, 'scroll', action, this,
8921 {buffer: tm == 'number' ? monitorScroll : 50});
8923 action.call(this); // align immediately
8927 * Clears any opacity settings from this element. Required in some cases for IE.
8928 * @return {Roo.Element} this
8930 clearOpacity : function(){
8931 if (window.ActiveXObject) {
8932 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8933 this.dom.style.filter = "";
8936 this.dom.style.opacity = "";
8937 this.dom.style["-moz-opacity"] = "";
8938 this.dom.style["-khtml-opacity"] = "";
8944 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8945 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8946 * @return {Roo.Element} this
8948 hide : function(animate){
8949 this.setVisible(false, this.preanim(arguments, 0));
8954 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8955 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8956 * @return {Roo.Element} this
8958 show : function(animate){
8959 this.setVisible(true, this.preanim(arguments, 0));
8964 * @private Test if size has a unit, otherwise appends the default
8966 addUnits : function(size){
8967 return Roo.Element.addUnits(size, this.defaultUnit);
8971 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8972 * @return {Roo.Element} this
8974 beginMeasure : function(){
8976 if(el.offsetWidth || el.offsetHeight){
8977 return this; // offsets work already
8980 var p = this.dom, b = document.body; // start with this element
8981 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8982 var pe = Roo.get(p);
8983 if(pe.getStyle('display') == 'none'){
8984 changed.push({el: p, visibility: pe.getStyle("visibility")});
8985 p.style.visibility = "hidden";
8986 p.style.display = "block";
8990 this._measureChanged = changed;
8996 * Restores displays to before beginMeasure was called
8997 * @return {Roo.Element} this
8999 endMeasure : function(){
9000 var changed = this._measureChanged;
9002 for(var i = 0, len = changed.length; i < len; i++) {
9004 r.el.style.visibility = r.visibility;
9005 r.el.style.display = "none";
9007 this._measureChanged = null;
9013 * Update the innerHTML of this element, optionally searching for and processing scripts
9014 * @param {String} html The new HTML
9015 * @param {Boolean} loadScripts (optional) true to look for and process scripts
9016 * @param {Function} callback For async script loading you can be noticed when the update completes
9017 * @return {Roo.Element} this
9019 update : function(html, loadScripts, callback){
9020 if(typeof html == "undefined"){
9023 if(loadScripts !== true){
9024 this.dom.innerHTML = html;
9025 if(typeof callback == "function"){
9033 html += '<span id="' + id + '"></span>';
9035 E.onAvailable(id, function(){
9036 var hd = document.getElementsByTagName("head")[0];
9037 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9038 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9039 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9042 while(match = re.exec(html)){
9043 var attrs = match[1];
9044 var srcMatch = attrs ? attrs.match(srcRe) : false;
9045 if(srcMatch && srcMatch[2]){
9046 var s = document.createElement("script");
9047 s.src = srcMatch[2];
9048 var typeMatch = attrs.match(typeRe);
9049 if(typeMatch && typeMatch[2]){
9050 s.type = typeMatch[2];
9053 }else if(match[2] && match[2].length > 0){
9054 if(window.execScript) {
9055 window.execScript(match[2]);
9063 window.eval(match[2]);
9067 var el = document.getElementById(id);
9068 if(el){el.parentNode.removeChild(el);}
9069 if(typeof callback == "function"){
9073 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9078 * Direct access to the UpdateManager update() method (takes the same parameters).
9079 * @param {String/Function} url The url for this request or a function to call to get the url
9080 * @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}
9081 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9082 * @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.
9083 * @return {Roo.Element} this
9086 var um = this.getUpdateManager();
9087 um.update.apply(um, arguments);
9092 * Gets this element's UpdateManager
9093 * @return {Roo.UpdateManager} The UpdateManager
9095 getUpdateManager : function(){
9096 if(!this.updateManager){
9097 this.updateManager = new Roo.UpdateManager(this);
9099 return this.updateManager;
9103 * Disables text selection for this element (normalized across browsers)
9104 * @return {Roo.Element} this
9106 unselectable : function(){
9107 this.dom.unselectable = "on";
9108 this.swallowEvent("selectstart", true);
9109 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9110 this.addClass("x-unselectable");
9115 * Calculates the x, y to center this element on the screen
9116 * @return {Array} The x, y values [x, y]
9118 getCenterXY : function(){
9119 return this.getAlignToXY(document, 'c-c');
9123 * Centers the Element in either the viewport, or another Element.
9124 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9126 center : function(centerIn){
9127 this.alignTo(centerIn || document, 'c-c');
9132 * Tests various css rules/browsers to determine if this element uses a border box
9135 isBorderBox : function(){
9136 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9140 * Return a box {x, y, width, height} that can be used to set another elements
9141 * size/location to match this element.
9142 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9143 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9144 * @return {Object} box An object in the format {x, y, width, height}
9146 getBox : function(contentBox, local){
9151 var left = parseInt(this.getStyle("left"), 10) || 0;
9152 var top = parseInt(this.getStyle("top"), 10) || 0;
9155 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9157 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9159 var l = this.getBorderWidth("l")+this.getPadding("l");
9160 var r = this.getBorderWidth("r")+this.getPadding("r");
9161 var t = this.getBorderWidth("t")+this.getPadding("t");
9162 var b = this.getBorderWidth("b")+this.getPadding("b");
9163 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)};
9165 bx.right = bx.x + bx.width;
9166 bx.bottom = bx.y + bx.height;
9171 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9172 for more information about the sides.
9173 * @param {String} sides
9176 getFrameWidth : function(sides, onlyContentBox){
9177 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9181 * 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.
9182 * @param {Object} box The box to fill {x, y, width, height}
9183 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9184 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9185 * @return {Roo.Element} this
9187 setBox : function(box, adjust, animate){
9188 var w = box.width, h = box.height;
9189 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9190 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9191 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9193 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9198 * Forces the browser to repaint this element
9199 * @return {Roo.Element} this
9201 repaint : function(){
9203 this.addClass("x-repaint");
9204 setTimeout(function(){
9205 Roo.get(dom).removeClass("x-repaint");
9211 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9212 * then it returns the calculated width of the sides (see getPadding)
9213 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9214 * @return {Object/Number}
9216 getMargins : function(side){
9219 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9220 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9221 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9222 right: parseInt(this.getStyle("margin-right"), 10) || 0
9225 return this.addStyles(side, El.margins);
9230 addStyles : function(sides, styles){
9232 for(var i = 0, len = sides.length; i < len; i++){
9233 v = this.getStyle(styles[sides.charAt(i)]);
9235 w = parseInt(v, 10);
9243 * Creates a proxy element of this element
9244 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9245 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9246 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9247 * @return {Roo.Element} The new proxy element
9249 createProxy : function(config, renderTo, matchBox){
9251 renderTo = Roo.getDom(renderTo);
9253 renderTo = document.body;
9255 config = typeof config == "object" ?
9256 config : {tag : "div", cls: config};
9257 var proxy = Roo.DomHelper.append(renderTo, config, true);
9259 proxy.setBox(this.getBox());
9265 * Puts a mask over this element to disable user interaction. Requires core.css.
9266 * This method can only be applied to elements which accept child nodes.
9267 * @param {String} msg (optional) A message to display in the mask
9268 * @param {String} msgCls (optional) A css class to apply to the msg element
9269 * @return {Element} The mask element
9271 mask : function(msg, msgCls)
9273 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9274 this.setStyle("position", "relative");
9277 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9280 this.addClass("x-masked");
9281 this._mask.setDisplayed(true);
9286 while (dom && dom.style) {
9287 if (!isNaN(parseInt(dom.style.zIndex))) {
9288 z = Math.max(z, parseInt(dom.style.zIndex));
9290 dom = dom.parentNode;
9292 // if we are masking the body - then it hides everything..
9293 if (this.dom == document.body) {
9295 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9296 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9299 if(typeof msg == 'string'){
9301 this._maskMsg = Roo.DomHelper.append(this.dom, {
9302 cls: "roo-el-mask-msg",
9306 cls: 'fa fa-spinner fa-spin'
9314 var mm = this._maskMsg;
9315 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9316 if (mm.dom.lastChild) { // weird IE issue?
9317 mm.dom.lastChild.innerHTML = msg;
9319 mm.setDisplayed(true);
9321 mm.setStyle('z-index', z + 102);
9323 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9324 this._mask.setHeight(this.getHeight());
9326 this._mask.setStyle('z-index', z + 100);
9332 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9333 * it is cached for reuse.
9335 unmask : function(removeEl){
9337 if(removeEl === true){
9338 this._mask.remove();
9341 this._maskMsg.remove();
9342 delete this._maskMsg;
9345 this._mask.setDisplayed(false);
9347 this._maskMsg.setDisplayed(false);
9351 this.removeClass("x-masked");
9355 * Returns true if this element is masked
9358 isMasked : function(){
9359 return this._mask && this._mask.isVisible();
9363 * Creates an iframe shim for this element to keep selects and other windowed objects from
9365 * @return {Roo.Element} The new shim element
9367 createShim : function(){
9368 var el = document.createElement('iframe');
9369 el.frameBorder = 'no';
9370 el.className = 'roo-shim';
9371 if(Roo.isIE && Roo.isSecure){
9372 el.src = Roo.SSL_SECURE_URL;
9374 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9375 shim.autoBoxAdjust = false;
9380 * Removes this element from the DOM and deletes it from the cache
9382 remove : function(){
9383 if(this.dom.parentNode){
9384 this.dom.parentNode.removeChild(this.dom);
9386 delete El.cache[this.dom.id];
9390 * Sets up event handlers to add and remove a css class when the mouse is over this element
9391 * @param {String} className
9392 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9393 * mouseout events for children elements
9394 * @return {Roo.Element} this
9396 addClassOnOver : function(className, preventFlicker){
9397 this.on("mouseover", function(){
9398 Roo.fly(this, '_internal').addClass(className);
9400 var removeFn = function(e){
9401 if(preventFlicker !== true || !e.within(this, true)){
9402 Roo.fly(this, '_internal').removeClass(className);
9405 this.on("mouseout", removeFn, this.dom);
9410 * Sets up event handlers to add and remove a css class when this element has the focus
9411 * @param {String} className
9412 * @return {Roo.Element} this
9414 addClassOnFocus : function(className){
9415 this.on("focus", function(){
9416 Roo.fly(this, '_internal').addClass(className);
9418 this.on("blur", function(){
9419 Roo.fly(this, '_internal').removeClass(className);
9424 * 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)
9425 * @param {String} className
9426 * @return {Roo.Element} this
9428 addClassOnClick : function(className){
9430 this.on("mousedown", function(){
9431 Roo.fly(dom, '_internal').addClass(className);
9432 var d = Roo.get(document);
9433 var fn = function(){
9434 Roo.fly(dom, '_internal').removeClass(className);
9435 d.removeListener("mouseup", fn);
9437 d.on("mouseup", fn);
9443 * Stops the specified event from bubbling and optionally prevents the default action
9444 * @param {String} eventName
9445 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9446 * @return {Roo.Element} this
9448 swallowEvent : function(eventName, preventDefault){
9449 var fn = function(e){
9450 e.stopPropagation();
9455 if(eventName instanceof Array){
9456 for(var i = 0, len = eventName.length; i < len; i++){
9457 this.on(eventName[i], fn);
9461 this.on(eventName, fn);
9468 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9471 * Sizes this element to its parent element's dimensions performing
9472 * neccessary box adjustments.
9473 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9474 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9475 * @return {Roo.Element} this
9477 fitToParent : function(monitorResize, targetParent) {
9478 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9479 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9480 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9483 var p = Roo.get(targetParent || this.dom.parentNode);
9484 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9485 if (monitorResize === true) {
9486 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9487 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9493 * Gets the next sibling, skipping text nodes
9494 * @return {HTMLElement} The next sibling or null
9496 getNextSibling : function(){
9497 var n = this.dom.nextSibling;
9498 while(n && n.nodeType != 1){
9505 * Gets the previous sibling, skipping text nodes
9506 * @return {HTMLElement} The previous sibling or null
9508 getPrevSibling : function(){
9509 var n = this.dom.previousSibling;
9510 while(n && n.nodeType != 1){
9511 n = n.previousSibling;
9518 * Appends the passed element(s) to this element
9519 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9520 * @return {Roo.Element} this
9522 appendChild: function(el){
9529 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9530 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9531 * automatically generated with the specified attributes.
9532 * @param {HTMLElement} insertBefore (optional) a child element of this element
9533 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9534 * @return {Roo.Element} The new child element
9536 createChild: function(config, insertBefore, returnDom){
9537 config = config || {tag:'div'};
9539 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9541 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9545 * Appends this element to the passed element
9546 * @param {String/HTMLElement/Element} el The new parent element
9547 * @return {Roo.Element} this
9549 appendTo: function(el){
9550 el = Roo.getDom(el);
9551 el.appendChild(this.dom);
9556 * Inserts this element before the passed element in the DOM
9557 * @param {String/HTMLElement/Element} el The element to insert before
9558 * @return {Roo.Element} this
9560 insertBefore: function(el){
9561 el = Roo.getDom(el);
9562 el.parentNode.insertBefore(this.dom, el);
9567 * Inserts this element after the passed element in the DOM
9568 * @param {String/HTMLElement/Element} el The element to insert after
9569 * @return {Roo.Element} this
9571 insertAfter: function(el){
9572 el = Roo.getDom(el);
9573 el.parentNode.insertBefore(this.dom, el.nextSibling);
9578 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9579 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9580 * @return {Roo.Element} The new child
9582 insertFirst: function(el, returnDom){
9584 if(typeof el == 'object' && !el.nodeType){ // dh config
9585 return this.createChild(el, this.dom.firstChild, returnDom);
9587 el = Roo.getDom(el);
9588 this.dom.insertBefore(el, this.dom.firstChild);
9589 return !returnDom ? Roo.get(el) : el;
9594 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9595 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9596 * @param {String} where (optional) 'before' or 'after' defaults to before
9597 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9598 * @return {Roo.Element} the inserted Element
9600 insertSibling: function(el, where, returnDom){
9601 where = where ? where.toLowerCase() : 'before';
9603 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9605 if(typeof el == 'object' && !el.nodeType){ // dh config
9606 if(where == 'after' && !this.dom.nextSibling){
9607 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9609 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9613 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9614 where == 'before' ? this.dom : this.dom.nextSibling);
9623 * Creates and wraps this element with another element
9624 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9625 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9626 * @return {HTMLElement/Element} The newly created wrapper element
9628 wrap: function(config, returnDom){
9630 config = {tag: "div"};
9632 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9633 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9638 * Replaces the passed element with this element
9639 * @param {String/HTMLElement/Element} el The element to replace
9640 * @return {Roo.Element} this
9642 replace: function(el){
9644 this.insertBefore(el);
9650 * Inserts an html fragment into this element
9651 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9652 * @param {String} html The HTML fragment
9653 * @param {Boolean} returnEl True to return an Roo.Element
9654 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9656 insertHtml : function(where, html, returnEl){
9657 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9658 return returnEl ? Roo.get(el) : el;
9662 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9663 * @param {Object} o The object with the attributes
9664 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9665 * @return {Roo.Element} this
9667 set : function(o, useSet){
9669 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9671 if(attr == "style" || typeof o[attr] == "function") { continue; }
9673 el.className = o["cls"];
9676 el.setAttribute(attr, o[attr]);
9683 Roo.DomHelper.applyStyles(el, o.style);
9689 * Convenience method for constructing a KeyMap
9690 * @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:
9691 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9692 * @param {Function} fn The function to call
9693 * @param {Object} scope (optional) The scope of the function
9694 * @return {Roo.KeyMap} The KeyMap created
9696 addKeyListener : function(key, fn, scope){
9698 if(typeof key != "object" || key instanceof Array){
9714 return new Roo.KeyMap(this, config);
9718 * Creates a KeyMap for this element
9719 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9720 * @return {Roo.KeyMap} The KeyMap created
9722 addKeyMap : function(config){
9723 return new Roo.KeyMap(this, config);
9727 * Returns true if this element is scrollable.
9730 isScrollable : function(){
9732 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9736 * 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().
9737 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9738 * @param {Number} value The new scroll value
9739 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9740 * @return {Element} this
9743 scrollTo : function(side, value, animate){
9744 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9746 this.dom[prop] = value;
9748 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9749 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9755 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9756 * within this element's scrollable range.
9757 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9758 * @param {Number} distance How far to scroll the element in pixels
9759 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9760 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9761 * was scrolled as far as it could go.
9763 scroll : function(direction, distance, animate){
9764 if(!this.isScrollable()){
9768 var l = el.scrollLeft, t = el.scrollTop;
9769 var w = el.scrollWidth, h = el.scrollHeight;
9770 var cw = el.clientWidth, ch = el.clientHeight;
9771 direction = direction.toLowerCase();
9772 var scrolled = false;
9773 var a = this.preanim(arguments, 2);
9778 var v = Math.min(l + distance, w-cw);
9779 this.scrollTo("left", v, a);
9786 var v = Math.max(l - distance, 0);
9787 this.scrollTo("left", v, a);
9795 var v = Math.max(t - distance, 0);
9796 this.scrollTo("top", v, a);
9804 var v = Math.min(t + distance, h-ch);
9805 this.scrollTo("top", v, a);
9814 * Translates the passed page coordinates into left/top css values for this element
9815 * @param {Number/Array} x The page x or an array containing [x, y]
9816 * @param {Number} y The page y
9817 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9819 translatePoints : function(x, y){
9820 if(typeof x == 'object' || x instanceof Array){
9823 var p = this.getStyle('position');
9824 var o = this.getXY();
9826 var l = parseInt(this.getStyle('left'), 10);
9827 var t = parseInt(this.getStyle('top'), 10);
9830 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9833 t = (p == "relative") ? 0 : this.dom.offsetTop;
9836 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9840 * Returns the current scroll position of the element.
9841 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9843 getScroll : function(){
9844 var d = this.dom, doc = document;
9845 if(d == doc || d == doc.body){
9846 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9847 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9848 return {left: l, top: t};
9850 return {left: d.scrollLeft, top: d.scrollTop};
9855 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9856 * are convert to standard 6 digit hex color.
9857 * @param {String} attr The css attribute
9858 * @param {String} defaultValue The default value to use when a valid color isn't found
9859 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9862 getColor : function(attr, defaultValue, prefix){
9863 var v = this.getStyle(attr);
9864 if(!v || v == "transparent" || v == "inherit") {
9865 return defaultValue;
9867 var color = typeof prefix == "undefined" ? "#" : prefix;
9868 if(v.substr(0, 4) == "rgb("){
9869 var rvs = v.slice(4, v.length -1).split(",");
9870 for(var i = 0; i < 3; i++){
9871 var h = parseInt(rvs[i]).toString(16);
9878 if(v.substr(0, 1) == "#"){
9880 for(var i = 1; i < 4; i++){
9881 var c = v.charAt(i);
9884 }else if(v.length == 7){
9885 color += v.substr(1);
9889 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9893 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9894 * gradient background, rounded corners and a 4-way shadow.
9895 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9896 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9897 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9898 * @return {Roo.Element} this
9900 boxWrap : function(cls){
9901 cls = cls || 'x-box';
9902 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9903 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9908 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9909 * @param {String} namespace The namespace in which to look for the attribute
9910 * @param {String} name The attribute name
9911 * @return {String} The attribute value
9913 getAttributeNS : Roo.isIE ? function(ns, name){
9915 var type = typeof d[ns+":"+name];
9916 if(type != 'undefined' && type != 'unknown'){
9917 return d[ns+":"+name];
9920 } : function(ns, name){
9922 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9927 * Sets or Returns the value the dom attribute value
9928 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9929 * @param {String} value (optional) The value to set the attribute to
9930 * @return {String} The attribute value
9932 attr : function(name){
9933 if (arguments.length > 1) {
9934 this.dom.setAttribute(name, arguments[1]);
9935 return arguments[1];
9937 if (typeof(name) == 'object') {
9938 for(var i in name) {
9939 this.attr(i, name[i]);
9945 if (!this.dom.hasAttribute(name)) {
9948 return this.dom.getAttribute(name);
9955 var ep = El.prototype;
9958 * Appends an event handler (Shorthand for addListener)
9959 * @param {String} eventName The type of event to append
9960 * @param {Function} fn The method the event invokes
9961 * @param {Object} scope (optional) The scope (this object) of the fn
9962 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9965 ep.on = ep.addListener;
9967 ep.mon = ep.addListener;
9970 * Removes an event handler from this element (shorthand for removeListener)
9971 * @param {String} eventName the type of event to remove
9972 * @param {Function} fn the method the event invokes
9973 * @return {Roo.Element} this
9976 ep.un = ep.removeListener;
9979 * true to automatically adjust width and height settings for box-model issues (default to true)
9981 ep.autoBoxAdjust = true;
9984 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9987 El.addUnits = function(v, defaultUnit){
9988 if(v === "" || v == "auto"){
9991 if(v === undefined){
9994 if(typeof v == "number" || !El.unitPattern.test(v)){
9995 return v + (defaultUnit || 'px');
10000 // special markup used throughout Roo when box wrapping elements
10001 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>';
10003 * Visibility mode constant - Use visibility to hide element
10009 * Visibility mode constant - Use display to hide element
10015 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10016 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10017 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10029 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10030 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10031 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10032 * @return {Element} The Element object
10035 El.get = function(el){
10037 if(!el){ return null; }
10038 if(typeof el == "string"){ // element id
10039 if(!(elm = document.getElementById(el))){
10042 if(ex = El.cache[el]){
10045 ex = El.cache[el] = new El(elm);
10048 }else if(el.tagName){ // dom element
10052 if(ex = El.cache[id]){
10055 ex = El.cache[id] = new El(el);
10058 }else if(el instanceof El){
10060 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10061 // catch case where it hasn't been appended
10062 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10065 }else if(el.isComposite){
10067 }else if(el instanceof Array){
10068 return El.select(el);
10069 }else if(el == document){
10070 // create a bogus element object representing the document object
10072 var f = function(){};
10073 f.prototype = El.prototype;
10075 docEl.dom = document;
10083 El.uncache = function(el){
10084 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10086 delete El.cache[a[i].id || a[i]];
10092 // Garbage collection - uncache elements/purge listeners on orphaned elements
10093 // so we don't hold a reference and cause the browser to retain them
10094 El.garbageCollect = function(){
10095 if(!Roo.enableGarbageCollector){
10096 clearInterval(El.collectorThread);
10099 for(var eid in El.cache){
10100 var el = El.cache[eid], d = el.dom;
10101 // -------------------------------------------------------
10102 // Determining what is garbage:
10103 // -------------------------------------------------------
10105 // dom node is null, definitely garbage
10106 // -------------------------------------------------------
10108 // no parentNode == direct orphan, definitely garbage
10109 // -------------------------------------------------------
10110 // !d.offsetParent && !document.getElementById(eid)
10111 // display none elements have no offsetParent so we will
10112 // also try to look it up by it's id. However, check
10113 // offsetParent first so we don't do unneeded lookups.
10114 // This enables collection of elements that are not orphans
10115 // directly, but somewhere up the line they have an orphan
10117 // -------------------------------------------------------
10118 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10119 delete El.cache[eid];
10120 if(d && Roo.enableListenerCollection){
10126 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10130 El.Flyweight = function(dom){
10133 El.Flyweight.prototype = El.prototype;
10135 El._flyweights = {};
10137 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10138 * the dom node can be overwritten by other code.
10139 * @param {String/HTMLElement} el The dom node or id
10140 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10141 * prevent conflicts (e.g. internally Roo uses "_internal")
10143 * @return {Element} The shared Element object
10145 El.fly = function(el, named){
10146 named = named || '_global';
10147 el = Roo.getDom(el);
10151 if(!El._flyweights[named]){
10152 El._flyweights[named] = new El.Flyweight();
10154 El._flyweights[named].dom = el;
10155 return El._flyweights[named];
10159 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10160 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10161 * Shorthand of {@link Roo.Element#get}
10162 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10163 * @return {Element} The Element object
10169 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10170 * the dom node can be overwritten by other code.
10171 * Shorthand of {@link Roo.Element#fly}
10172 * @param {String/HTMLElement} el The dom node or id
10173 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10174 * prevent conflicts (e.g. internally Roo uses "_internal")
10176 * @return {Element} The shared Element object
10182 // speedy lookup for elements never to box adjust
10183 var noBoxAdjust = Roo.isStrict ? {
10186 input:1, select:1, textarea:1
10188 if(Roo.isIE || Roo.isGecko){
10189 noBoxAdjust['button'] = 1;
10193 Roo.EventManager.on(window, 'unload', function(){
10195 delete El._flyweights;
10203 Roo.Element.selectorFunction = Roo.DomQuery.select;
10206 Roo.Element.select = function(selector, unique, root){
10208 if(typeof selector == "string"){
10209 els = Roo.Element.selectorFunction(selector, root);
10210 }else if(selector.length !== undefined){
10213 throw "Invalid selector";
10215 if(unique === true){
10216 return new Roo.CompositeElement(els);
10218 return new Roo.CompositeElementLite(els);
10222 * Selects elements based on the passed CSS selector to enable working on them as 1.
10223 * @param {String/Array} selector The CSS selector or an array of elements
10224 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10225 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10226 * @return {CompositeElementLite/CompositeElement}
10230 Roo.select = Roo.Element.select;
10247 * Ext JS Library 1.1.1
10248 * Copyright(c) 2006-2007, Ext JS, LLC.
10250 * Originally Released Under LGPL - original licence link has changed is not relivant.
10253 * <script type="text/javascript">
10258 //Notifies Element that fx methods are available
10259 Roo.enableFx = true;
10263 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10264 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10265 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10266 * Element effects to work.</p><br/>
10268 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10269 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10270 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10271 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10272 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10273 * expected results and should be done with care.</p><br/>
10275 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10276 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10279 ----- -----------------------------
10280 tl The top left corner
10281 t The center of the top edge
10282 tr The top right corner
10283 l The center of the left edge
10284 r The center of the right edge
10285 bl The bottom left corner
10286 b The center of the bottom edge
10287 br The bottom right corner
10289 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10290 * below are common options that can be passed to any Fx method.</b>
10291 * @cfg {Function} callback A function called when the effect is finished
10292 * @cfg {Object} scope The scope of the effect function
10293 * @cfg {String} easing A valid Easing value for the effect
10294 * @cfg {String} afterCls A css class to apply after the effect
10295 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10296 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10297 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10298 * effects that end with the element being visually hidden, ignored otherwise)
10299 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10300 * a function which returns such a specification that will be applied to the Element after the effect finishes
10301 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10302 * @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
10303 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10307 * Slides the element into view. An anchor point can be optionally passed to set the point of
10308 * origin for the slide effect. This function automatically handles wrapping the element with
10309 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10312 // default: slide the element in from the top
10315 // custom: slide the element in from the right with a 2-second duration
10316 el.slideIn('r', { duration: 2 });
10318 // common config options shown with default values
10324 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10325 * @param {Object} options (optional) Object literal with any of the Fx config options
10326 * @return {Roo.Element} The Element
10328 slideIn : function(anchor, o){
10329 var el = this.getFxEl();
10332 el.queueFx(o, function(){
10334 anchor = anchor || "t";
10336 // fix display to visibility
10339 // restore values after effect
10340 var r = this.getFxRestore();
10341 var b = this.getBox();
10342 // fixed size for slide
10346 var wrap = this.fxWrap(r.pos, o, "hidden");
10348 var st = this.dom.style;
10349 st.visibility = "visible";
10350 st.position = "absolute";
10352 // clear out temp styles after slide and unwrap
10353 var after = function(){
10354 el.fxUnwrap(wrap, r.pos, o);
10355 st.width = r.width;
10356 st.height = r.height;
10359 // time to calc the positions
10360 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10362 switch(anchor.toLowerCase()){
10364 wrap.setSize(b.width, 0);
10365 st.left = st.bottom = "0";
10369 wrap.setSize(0, b.height);
10370 st.right = st.top = "0";
10374 wrap.setSize(0, b.height);
10375 wrap.setX(b.right);
10376 st.left = st.top = "0";
10377 a = {width: bw, points: pt};
10380 wrap.setSize(b.width, 0);
10381 wrap.setY(b.bottom);
10382 st.left = st.top = "0";
10383 a = {height: bh, points: pt};
10386 wrap.setSize(0, 0);
10387 st.right = st.bottom = "0";
10388 a = {width: bw, height: bh};
10391 wrap.setSize(0, 0);
10392 wrap.setY(b.y+b.height);
10393 st.right = st.top = "0";
10394 a = {width: bw, height: bh, points: pt};
10397 wrap.setSize(0, 0);
10398 wrap.setXY([b.right, b.bottom]);
10399 st.left = st.top = "0";
10400 a = {width: bw, height: bh, points: pt};
10403 wrap.setSize(0, 0);
10404 wrap.setX(b.x+b.width);
10405 st.left = st.bottom = "0";
10406 a = {width: bw, height: bh, points: pt};
10409 this.dom.style.visibility = "visible";
10412 arguments.callee.anim = wrap.fxanim(a,
10422 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10423 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10424 * 'hidden') but block elements will still take up space in the document. The element must be removed
10425 * from the DOM using the 'remove' config option if desired. This function automatically handles
10426 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10429 // default: slide the element out to the top
10432 // custom: slide the element out to the right with a 2-second duration
10433 el.slideOut('r', { duration: 2 });
10435 // common config options shown with default values
10443 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10444 * @param {Object} options (optional) Object literal with any of the Fx config options
10445 * @return {Roo.Element} The Element
10447 slideOut : function(anchor, o){
10448 var el = this.getFxEl();
10451 el.queueFx(o, function(){
10453 anchor = anchor || "t";
10455 // restore values after effect
10456 var r = this.getFxRestore();
10458 var b = this.getBox();
10459 // fixed size for slide
10463 var wrap = this.fxWrap(r.pos, o, "visible");
10465 var st = this.dom.style;
10466 st.visibility = "visible";
10467 st.position = "absolute";
10471 var after = function(){
10473 el.setDisplayed(false);
10478 el.fxUnwrap(wrap, r.pos, o);
10480 st.width = r.width;
10481 st.height = r.height;
10486 var a, zero = {to: 0};
10487 switch(anchor.toLowerCase()){
10489 st.left = st.bottom = "0";
10490 a = {height: zero};
10493 st.right = st.top = "0";
10497 st.left = st.top = "0";
10498 a = {width: zero, points: {to:[b.right, b.y]}};
10501 st.left = st.top = "0";
10502 a = {height: zero, points: {to:[b.x, b.bottom]}};
10505 st.right = st.bottom = "0";
10506 a = {width: zero, height: zero};
10509 st.right = st.top = "0";
10510 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10513 st.left = st.top = "0";
10514 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10517 st.left = st.bottom = "0";
10518 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10522 arguments.callee.anim = wrap.fxanim(a,
10532 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10533 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10534 * The element must be removed from the DOM using the 'remove' config option if desired.
10540 // common config options shown with default values
10548 * @param {Object} options (optional) Object literal with any of the Fx config options
10549 * @return {Roo.Element} The Element
10551 puff : function(o){
10552 var el = this.getFxEl();
10555 el.queueFx(o, function(){
10556 this.clearOpacity();
10559 // restore values after effect
10560 var r = this.getFxRestore();
10561 var st = this.dom.style;
10563 var after = function(){
10565 el.setDisplayed(false);
10572 el.setPositioning(r.pos);
10573 st.width = r.width;
10574 st.height = r.height;
10579 var width = this.getWidth();
10580 var height = this.getHeight();
10582 arguments.callee.anim = this.fxanim({
10583 width : {to: this.adjustWidth(width * 2)},
10584 height : {to: this.adjustHeight(height * 2)},
10585 points : {by: [-(width * .5), -(height * .5)]},
10587 fontSize: {to:200, unit: "%"}
10598 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10599 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10600 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10606 // all config options shown with default values
10614 * @param {Object} options (optional) Object literal with any of the Fx config options
10615 * @return {Roo.Element} The Element
10617 switchOff : function(o){
10618 var el = this.getFxEl();
10621 el.queueFx(o, function(){
10622 this.clearOpacity();
10625 // restore values after effect
10626 var r = this.getFxRestore();
10627 var st = this.dom.style;
10629 var after = function(){
10631 el.setDisplayed(false);
10637 el.setPositioning(r.pos);
10638 st.width = r.width;
10639 st.height = r.height;
10644 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10645 this.clearOpacity();
10649 points:{by:[0, this.getHeight() * .5]}
10650 }, o, 'motion', 0.3, 'easeIn', after);
10651 }).defer(100, this);
10658 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10659 * changed using the "attr" config option) and then fading back to the original color. If no original
10660 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10663 // default: highlight background to yellow
10666 // custom: highlight foreground text to blue for 2 seconds
10667 el.highlight("0000ff", { attr: 'color', duration: 2 });
10669 // common config options shown with default values
10670 el.highlight("ffff9c", {
10671 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10672 endColor: (current color) or "ffffff",
10677 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10678 * @param {Object} options (optional) Object literal with any of the Fx config options
10679 * @return {Roo.Element} The Element
10681 highlight : function(color, o){
10682 var el = this.getFxEl();
10685 el.queueFx(o, function(){
10686 color = color || "ffff9c";
10687 attr = o.attr || "backgroundColor";
10689 this.clearOpacity();
10692 var origColor = this.getColor(attr);
10693 var restoreColor = this.dom.style[attr];
10694 endColor = (o.endColor || origColor) || "ffffff";
10696 var after = function(){
10697 el.dom.style[attr] = restoreColor;
10702 a[attr] = {from: color, to: endColor};
10703 arguments.callee.anim = this.fxanim(a,
10713 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10716 // default: a single light blue ripple
10719 // custom: 3 red ripples lasting 3 seconds total
10720 el.frame("ff0000", 3, { duration: 3 });
10722 // common config options shown with default values
10723 el.frame("C3DAF9", 1, {
10724 duration: 1 //duration of entire animation (not each individual ripple)
10725 // Note: Easing is not configurable and will be ignored if included
10728 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10729 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10730 * @param {Object} options (optional) Object literal with any of the Fx config options
10731 * @return {Roo.Element} The Element
10733 frame : function(color, count, o){
10734 var el = this.getFxEl();
10737 el.queueFx(o, function(){
10738 color = color || "#C3DAF9";
10739 if(color.length == 6){
10740 color = "#" + color;
10742 count = count || 1;
10743 duration = o.duration || 1;
10746 var b = this.getBox();
10747 var animFn = function(){
10748 var proxy = this.createProxy({
10751 visbility:"hidden",
10752 position:"absolute",
10753 "z-index":"35000", // yee haw
10754 border:"0px solid " + color
10757 var scale = Roo.isBorderBox ? 2 : 1;
10759 top:{from:b.y, to:b.y - 20},
10760 left:{from:b.x, to:b.x - 20},
10761 borderWidth:{from:0, to:10},
10762 opacity:{from:1, to:0},
10763 height:{from:b.height, to:(b.height + (20*scale))},
10764 width:{from:b.width, to:(b.width + (20*scale))}
10765 }, duration, function(){
10769 animFn.defer((duration/2)*1000, this);
10780 * Creates a pause before any subsequent queued effects begin. If there are
10781 * no effects queued after the pause it will have no effect.
10786 * @param {Number} seconds The length of time to pause (in seconds)
10787 * @return {Roo.Element} The Element
10789 pause : function(seconds){
10790 var el = this.getFxEl();
10793 el.queueFx(o, function(){
10794 setTimeout(function(){
10796 }, seconds * 1000);
10802 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10803 * using the "endOpacity" config option.
10806 // default: fade in from opacity 0 to 100%
10809 // custom: fade in from opacity 0 to 75% over 2 seconds
10810 el.fadeIn({ endOpacity: .75, duration: 2});
10812 // common config options shown with default values
10814 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10819 * @param {Object} options (optional) Object literal with any of the Fx config options
10820 * @return {Roo.Element} The Element
10822 fadeIn : function(o){
10823 var el = this.getFxEl();
10825 el.queueFx(o, function(){
10826 this.setOpacity(0);
10828 this.dom.style.visibility = 'visible';
10829 var to = o.endOpacity || 1;
10830 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10831 o, null, .5, "easeOut", function(){
10833 this.clearOpacity();
10842 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10843 * using the "endOpacity" config option.
10846 // default: fade out from the element's current opacity to 0
10849 // custom: fade out from the element's current opacity to 25% over 2 seconds
10850 el.fadeOut({ endOpacity: .25, duration: 2});
10852 // common config options shown with default values
10854 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10861 * @param {Object} options (optional) Object literal with any of the Fx config options
10862 * @return {Roo.Element} The Element
10864 fadeOut : function(o){
10865 var el = this.getFxEl();
10867 el.queueFx(o, function(){
10868 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10869 o, null, .5, "easeOut", function(){
10870 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10871 this.dom.style.display = "none";
10873 this.dom.style.visibility = "hidden";
10875 this.clearOpacity();
10883 * Animates the transition of an element's dimensions from a starting height/width
10884 * to an ending height/width.
10887 // change height and width to 100x100 pixels
10888 el.scale(100, 100);
10890 // common config options shown with default values. The height and width will default to
10891 // the element's existing values if passed as null.
10894 [element's height], {
10899 * @param {Number} width The new width (pass undefined to keep the original width)
10900 * @param {Number} height The new height (pass undefined to keep the original height)
10901 * @param {Object} options (optional) Object literal with any of the Fx config options
10902 * @return {Roo.Element} The Element
10904 scale : function(w, h, o){
10905 this.shift(Roo.apply({}, o, {
10913 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10914 * Any of these properties not specified in the config object will not be changed. This effect
10915 * requires that at least one new dimension, position or opacity setting must be passed in on
10916 * the config object in order for the function to have any effect.
10919 // slide the element horizontally to x position 200 while changing the height and opacity
10920 el.shift({ x: 200, height: 50, opacity: .8 });
10922 // common config options shown with default values.
10924 width: [element's width],
10925 height: [element's height],
10926 x: [element's x position],
10927 y: [element's y position],
10928 opacity: [element's opacity],
10933 * @param {Object} options Object literal with any of the Fx config options
10934 * @return {Roo.Element} The Element
10936 shift : function(o){
10937 var el = this.getFxEl();
10939 el.queueFx(o, function(){
10940 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10941 if(w !== undefined){
10942 a.width = {to: this.adjustWidth(w)};
10944 if(h !== undefined){
10945 a.height = {to: this.adjustHeight(h)};
10947 if(x !== undefined || y !== undefined){
10949 x !== undefined ? x : this.getX(),
10950 y !== undefined ? y : this.getY()
10953 if(op !== undefined){
10954 a.opacity = {to: op};
10956 if(o.xy !== undefined){
10957 a.points = {to: o.xy};
10959 arguments.callee.anim = this.fxanim(a,
10960 o, 'motion', .35, "easeOut", function(){
10968 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10969 * ending point of the effect.
10972 // default: slide the element downward while fading out
10975 // custom: slide the element out to the right with a 2-second duration
10976 el.ghost('r', { duration: 2 });
10978 // common config options shown with default values
10986 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10987 * @param {Object} options (optional) Object literal with any of the Fx config options
10988 * @return {Roo.Element} The Element
10990 ghost : function(anchor, o){
10991 var el = this.getFxEl();
10994 el.queueFx(o, function(){
10995 anchor = anchor || "b";
10997 // restore values after effect
10998 var r = this.getFxRestore();
10999 var w = this.getWidth(),
11000 h = this.getHeight();
11002 var st = this.dom.style;
11004 var after = function(){
11006 el.setDisplayed(false);
11012 el.setPositioning(r.pos);
11013 st.width = r.width;
11014 st.height = r.height;
11019 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11020 switch(anchor.toLowerCase()){
11047 arguments.callee.anim = this.fxanim(a,
11057 * Ensures that all effects queued after syncFx is called on the element are
11058 * run concurrently. This is the opposite of {@link #sequenceFx}.
11059 * @return {Roo.Element} The Element
11061 syncFx : function(){
11062 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11071 * Ensures that all effects queued after sequenceFx is called on the element are
11072 * run in sequence. This is the opposite of {@link #syncFx}.
11073 * @return {Roo.Element} The Element
11075 sequenceFx : function(){
11076 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11078 concurrent : false,
11085 nextFx : function(){
11086 var ef = this.fxQueue[0];
11093 * Returns true if the element has any effects actively running or queued, else returns false.
11094 * @return {Boolean} True if element has active effects, else false
11096 hasActiveFx : function(){
11097 return this.fxQueue && this.fxQueue[0];
11101 * Stops any running effects and clears the element's internal effects queue if it contains
11102 * any additional effects that haven't started yet.
11103 * @return {Roo.Element} The Element
11105 stopFx : function(){
11106 if(this.hasActiveFx()){
11107 var cur = this.fxQueue[0];
11108 if(cur && cur.anim && cur.anim.isAnimated()){
11109 this.fxQueue = [cur]; // clear out others
11110 cur.anim.stop(true);
11117 beforeFx : function(o){
11118 if(this.hasActiveFx() && !o.concurrent){
11129 * Returns true if the element is currently blocking so that no other effect can be queued
11130 * until this effect is finished, else returns false if blocking is not set. This is commonly
11131 * used to ensure that an effect initiated by a user action runs to completion prior to the
11132 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11133 * @return {Boolean} True if blocking, else false
11135 hasFxBlock : function(){
11136 var q = this.fxQueue;
11137 return q && q[0] && q[0].block;
11141 queueFx : function(o, fn){
11145 if(!this.hasFxBlock()){
11146 Roo.applyIf(o, this.fxDefaults);
11148 var run = this.beforeFx(o);
11149 fn.block = o.block;
11150 this.fxQueue.push(fn);
11162 fxWrap : function(pos, o, vis){
11164 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11167 wrapXY = this.getXY();
11169 var div = document.createElement("div");
11170 div.style.visibility = vis;
11171 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11172 wrap.setPositioning(pos);
11173 if(wrap.getStyle("position") == "static"){
11174 wrap.position("relative");
11176 this.clearPositioning('auto');
11178 wrap.dom.appendChild(this.dom);
11180 wrap.setXY(wrapXY);
11187 fxUnwrap : function(wrap, pos, o){
11188 this.clearPositioning();
11189 this.setPositioning(pos);
11191 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11197 getFxRestore : function(){
11198 var st = this.dom.style;
11199 return {pos: this.getPositioning(), width: st.width, height : st.height};
11203 afterFx : function(o){
11205 this.applyStyles(o.afterStyle);
11208 this.addClass(o.afterCls);
11210 if(o.remove === true){
11213 Roo.callback(o.callback, o.scope, [this]);
11215 this.fxQueue.shift();
11221 getFxEl : function(){ // support for composite element fx
11222 return Roo.get(this.dom);
11226 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11227 animType = animType || 'run';
11229 var anim = Roo.lib.Anim[animType](
11231 (opt.duration || defaultDur) || .35,
11232 (opt.easing || defaultEase) || 'easeOut',
11234 Roo.callback(cb, this);
11243 // backwords compat
11244 Roo.Fx.resize = Roo.Fx.scale;
11246 //When included, Roo.Fx is automatically applied to Element so that all basic
11247 //effects are available directly via the Element API
11248 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11250 * Ext JS Library 1.1.1
11251 * Copyright(c) 2006-2007, Ext JS, LLC.
11253 * Originally Released Under LGPL - original licence link has changed is not relivant.
11256 * <script type="text/javascript">
11261 * @class Roo.CompositeElement
11262 * Standard composite class. Creates a Roo.Element for every element in the collection.
11264 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11265 * actions will be performed on all the elements in this collection.</b>
11267 * All methods return <i>this</i> and can be chained.
11269 var els = Roo.select("#some-el div.some-class", true);
11270 // or select directly from an existing element
11271 var el = Roo.get('some-el');
11272 el.select('div.some-class', true);
11274 els.setWidth(100); // all elements become 100 width
11275 els.hide(true); // all elements fade out and hide
11277 els.setWidth(100).hide(true);
11280 Roo.CompositeElement = function(els){
11281 this.elements = [];
11282 this.addElements(els);
11284 Roo.CompositeElement.prototype = {
11286 addElements : function(els){
11290 if(typeof els == "string"){
11291 els = Roo.Element.selectorFunction(els);
11293 var yels = this.elements;
11294 var index = yels.length-1;
11295 for(var i = 0, len = els.length; i < len; i++) {
11296 yels[++index] = Roo.get(els[i]);
11302 * Clears this composite and adds the elements returned by the passed selector.
11303 * @param {String/Array} els A string CSS selector, an array of elements or an element
11304 * @return {CompositeElement} this
11306 fill : function(els){
11307 this.elements = [];
11313 * Filters this composite to only elements that match the passed selector.
11314 * @param {String} selector A string CSS selector
11315 * @param {Boolean} inverse return inverse filter (not matches)
11316 * @return {CompositeElement} this
11318 filter : function(selector, inverse){
11320 inverse = inverse || false;
11321 this.each(function(el){
11322 var match = inverse ? !el.is(selector) : el.is(selector);
11324 els[els.length] = el.dom;
11331 invoke : function(fn, args){
11332 var els = this.elements;
11333 for(var i = 0, len = els.length; i < len; i++) {
11334 Roo.Element.prototype[fn].apply(els[i], args);
11339 * Adds elements to this composite.
11340 * @param {String/Array} els A string CSS selector, an array of elements or an element
11341 * @return {CompositeElement} this
11343 add : function(els){
11344 if(typeof els == "string"){
11345 this.addElements(Roo.Element.selectorFunction(els));
11346 }else if(els.length !== undefined){
11347 this.addElements(els);
11349 this.addElements([els]);
11354 * Calls the passed function passing (el, this, index) for each element in this composite.
11355 * @param {Function} fn The function to call
11356 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11357 * @return {CompositeElement} this
11359 each : function(fn, scope){
11360 var els = this.elements;
11361 for(var i = 0, len = els.length; i < len; i++){
11362 if(fn.call(scope || els[i], els[i], this, i) === false) {
11370 * Returns the Element object at the specified index
11371 * @param {Number} index
11372 * @return {Roo.Element}
11374 item : function(index){
11375 return this.elements[index] || null;
11379 * Returns the first Element
11380 * @return {Roo.Element}
11382 first : function(){
11383 return this.item(0);
11387 * Returns the last Element
11388 * @return {Roo.Element}
11391 return this.item(this.elements.length-1);
11395 * Returns the number of elements in this composite
11398 getCount : function(){
11399 return this.elements.length;
11403 * Returns true if this composite contains the passed element
11406 contains : function(el){
11407 return this.indexOf(el) !== -1;
11411 * Returns true if this composite contains the passed element
11414 indexOf : function(el){
11415 return this.elements.indexOf(Roo.get(el));
11420 * Removes the specified element(s).
11421 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11422 * or an array of any of those.
11423 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11424 * @return {CompositeElement} this
11426 removeElement : function(el, removeDom){
11427 if(el instanceof Array){
11428 for(var i = 0, len = el.length; i < len; i++){
11429 this.removeElement(el[i]);
11433 var index = typeof el == 'number' ? el : this.indexOf(el);
11436 var d = this.elements[index];
11440 d.parentNode.removeChild(d);
11443 this.elements.splice(index, 1);
11449 * Replaces the specified element with the passed element.
11450 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11452 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11453 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11454 * @return {CompositeElement} this
11456 replaceElement : function(el, replacement, domReplace){
11457 var index = typeof el == 'number' ? el : this.indexOf(el);
11460 this.elements[index].replaceWith(replacement);
11462 this.elements.splice(index, 1, Roo.get(replacement))
11469 * Removes all elements.
11471 clear : function(){
11472 this.elements = [];
11476 Roo.CompositeElement.createCall = function(proto, fnName){
11477 if(!proto[fnName]){
11478 proto[fnName] = function(){
11479 return this.invoke(fnName, arguments);
11483 for(var fnName in Roo.Element.prototype){
11484 if(typeof Roo.Element.prototype[fnName] == "function"){
11485 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11491 * Ext JS Library 1.1.1
11492 * Copyright(c) 2006-2007, Ext JS, LLC.
11494 * Originally Released Under LGPL - original licence link has changed is not relivant.
11497 * <script type="text/javascript">
11501 * @class Roo.CompositeElementLite
11502 * @extends Roo.CompositeElement
11503 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11505 var els = Roo.select("#some-el div.some-class");
11506 // or select directly from an existing element
11507 var el = Roo.get('some-el');
11508 el.select('div.some-class');
11510 els.setWidth(100); // all elements become 100 width
11511 els.hide(true); // all elements fade out and hide
11513 els.setWidth(100).hide(true);
11514 </code></pre><br><br>
11515 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11516 * actions will be performed on all the elements in this collection.</b>
11518 Roo.CompositeElementLite = function(els){
11519 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11520 this.el = new Roo.Element.Flyweight();
11522 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11523 addElements : function(els){
11525 if(els instanceof Array){
11526 this.elements = this.elements.concat(els);
11528 var yels = this.elements;
11529 var index = yels.length-1;
11530 for(var i = 0, len = els.length; i < len; i++) {
11531 yels[++index] = els[i];
11537 invoke : function(fn, args){
11538 var els = this.elements;
11540 for(var i = 0, len = els.length; i < len; i++) {
11542 Roo.Element.prototype[fn].apply(el, args);
11547 * Returns a flyweight Element of the dom element object at the specified index
11548 * @param {Number} index
11549 * @return {Roo.Element}
11551 item : function(index){
11552 if(!this.elements[index]){
11555 this.el.dom = this.elements[index];
11559 // fixes scope with flyweight
11560 addListener : function(eventName, handler, scope, opt){
11561 var els = this.elements;
11562 for(var i = 0, len = els.length; i < len; i++) {
11563 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11569 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11570 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11571 * a reference to the dom node, use el.dom.</b>
11572 * @param {Function} fn The function to call
11573 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11574 * @return {CompositeElement} this
11576 each : function(fn, scope){
11577 var els = this.elements;
11579 for(var i = 0, len = els.length; i < len; i++){
11581 if(fn.call(scope || el, el, this, i) === false){
11588 indexOf : function(el){
11589 return this.elements.indexOf(Roo.getDom(el));
11592 replaceElement : function(el, replacement, domReplace){
11593 var index = typeof el == 'number' ? el : this.indexOf(el);
11595 replacement = Roo.getDom(replacement);
11597 var d = this.elements[index];
11598 d.parentNode.insertBefore(replacement, d);
11599 d.parentNode.removeChild(d);
11601 this.elements.splice(index, 1, replacement);
11606 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11610 * Ext JS Library 1.1.1
11611 * Copyright(c) 2006-2007, Ext JS, LLC.
11613 * Originally Released Under LGPL - original licence link has changed is not relivant.
11616 * <script type="text/javascript">
11622 * @class Roo.data.Connection
11623 * @extends Roo.util.Observable
11624 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11625 * either to a configured URL, or to a URL specified at request time.
11627 * Requests made by this class are asynchronous, and will return immediately. No data from
11628 * the server will be available to the statement immediately following the {@link #request} call.
11629 * To process returned data, use a callback in the request options object, or an event listener.
11631 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11632 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11633 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11634 * property and, if present, the IFRAME's XML document as the responseXML property.
11636 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11637 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11638 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11639 * standard DOM methods.
11641 * @param {Object} config a configuration object.
11643 Roo.data.Connection = function(config){
11644 Roo.apply(this, config);
11647 * @event beforerequest
11648 * Fires before a network request is made to retrieve a data object.
11649 * @param {Connection} conn This Connection object.
11650 * @param {Object} options The options config object passed to the {@link #request} method.
11652 "beforerequest" : true,
11654 * @event requestcomplete
11655 * Fires if the request was successfully completed.
11656 * @param {Connection} conn This Connection object.
11657 * @param {Object} response The XHR object containing the response data.
11658 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11659 * @param {Object} options The options config object passed to the {@link #request} method.
11661 "requestcomplete" : true,
11663 * @event requestexception
11664 * Fires if an error HTTP status was returned from the server.
11665 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11666 * @param {Connection} conn This Connection object.
11667 * @param {Object} response The XHR object containing the response data.
11668 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11669 * @param {Object} options The options config object passed to the {@link #request} method.
11671 "requestexception" : true
11673 Roo.data.Connection.superclass.constructor.call(this);
11676 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11678 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11681 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11682 * extra parameters to each request made by this object. (defaults to undefined)
11685 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11686 * to each request made by this object. (defaults to undefined)
11689 * @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)
11692 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11696 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11702 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11705 disableCaching: true,
11708 * Sends an HTTP request to a remote server.
11709 * @param {Object} options An object which may contain the following properties:<ul>
11710 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11711 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11712 * request, a url encoded string or a function to call to get either.</li>
11713 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11714 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11715 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11716 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11717 * <li>options {Object} The parameter to the request call.</li>
11718 * <li>success {Boolean} True if the request succeeded.</li>
11719 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11721 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11722 * The callback is passed the following parameters:<ul>
11723 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11724 * <li>options {Object} The parameter to the request call.</li>
11726 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11727 * The callback is passed the following parameters:<ul>
11728 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11729 * <li>options {Object} The parameter to the request call.</li>
11731 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11732 * for the callback function. Defaults to the browser window.</li>
11733 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11734 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11735 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11736 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11737 * params for the post data. Any params will be appended to the URL.</li>
11738 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11740 * @return {Number} transactionId
11742 request : function(o){
11743 if(this.fireEvent("beforerequest", this, o) !== false){
11746 if(typeof p == "function"){
11747 p = p.call(o.scope||window, o);
11749 if(typeof p == "object"){
11750 p = Roo.urlEncode(o.params);
11752 if(this.extraParams){
11753 var extras = Roo.urlEncode(this.extraParams);
11754 p = p ? (p + '&' + extras) : extras;
11757 var url = o.url || this.url;
11758 if(typeof url == 'function'){
11759 url = url.call(o.scope||window, o);
11763 var form = Roo.getDom(o.form);
11764 url = url || form.action;
11766 var enctype = form.getAttribute("enctype");
11769 return this.doFormDataUpload(o, url);
11772 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11773 return this.doFormUpload(o, p, url);
11775 var f = Roo.lib.Ajax.serializeForm(form);
11776 p = p ? (p + '&' + f) : f;
11779 if (!o.form && o.formData) {
11780 o.formData = o.formData === true ? new FormData() : o.formData;
11781 for (var k in o.params) {
11782 o.formData.append(k,o.params[k]);
11785 return this.doFormDataUpload(o, url);
11789 var hs = o.headers;
11790 if(this.defaultHeaders){
11791 hs = Roo.apply(hs || {}, this.defaultHeaders);
11798 success: this.handleResponse,
11799 failure: this.handleFailure,
11801 argument: {options: o},
11802 timeout : o.timeout || this.timeout
11805 var method = o.method||this.method||(p ? "POST" : "GET");
11807 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11808 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11811 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11815 }else if(this.autoAbort !== false){
11819 if((method == 'GET' && p) || o.xmlData){
11820 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11823 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11824 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11825 Roo.lib.Ajax.useDefaultHeader == true;
11826 return this.transId;
11828 Roo.callback(o.callback, o.scope, [o, null, null]);
11834 * Determine whether this object has a request outstanding.
11835 * @param {Number} transactionId (Optional) defaults to the last transaction
11836 * @return {Boolean} True if there is an outstanding request.
11838 isLoading : function(transId){
11840 return Roo.lib.Ajax.isCallInProgress(transId);
11842 return this.transId ? true : false;
11847 * Aborts any outstanding request.
11848 * @param {Number} transactionId (Optional) defaults to the last transaction
11850 abort : function(transId){
11851 if(transId || this.isLoading()){
11852 Roo.lib.Ajax.abort(transId || this.transId);
11857 handleResponse : function(response){
11858 this.transId = false;
11859 var options = response.argument.options;
11860 response.argument = options ? options.argument : null;
11861 this.fireEvent("requestcomplete", this, response, options);
11862 Roo.callback(options.success, options.scope, [response, options]);
11863 Roo.callback(options.callback, options.scope, [options, true, response]);
11867 handleFailure : function(response, e){
11868 this.transId = false;
11869 var options = response.argument.options;
11870 response.argument = options ? options.argument : null;
11871 this.fireEvent("requestexception", this, response, options, e);
11872 Roo.callback(options.failure, options.scope, [response, options]);
11873 Roo.callback(options.callback, options.scope, [options, false, response]);
11877 doFormUpload : function(o, ps, url){
11879 var frame = document.createElement('iframe');
11882 frame.className = 'x-hidden';
11884 frame.src = Roo.SSL_SECURE_URL;
11886 document.body.appendChild(frame);
11889 document.frames[id].name = id;
11892 var form = Roo.getDom(o.form);
11894 form.method = 'POST';
11895 form.enctype = form.encoding = 'multipart/form-data';
11901 if(ps){ // add dynamic params
11903 ps = Roo.urlDecode(ps, false);
11905 if(ps.hasOwnProperty(k)){
11906 hd = document.createElement('input');
11907 hd.type = 'hidden';
11910 form.appendChild(hd);
11917 var r = { // bogus response object
11922 r.argument = o ? o.argument : null;
11927 doc = frame.contentWindow.document;
11929 doc = (frame.contentDocument || window.frames[id].document);
11931 if(doc && doc.body){
11932 r.responseText = doc.body.innerHTML;
11934 if(doc && doc.XMLDocument){
11935 r.responseXML = doc.XMLDocument;
11937 r.responseXML = doc;
11944 Roo.EventManager.removeListener(frame, 'load', cb, this);
11946 this.fireEvent("requestcomplete", this, r, o);
11947 Roo.callback(o.success, o.scope, [r, o]);
11948 Roo.callback(o.callback, o.scope, [o, true, r]);
11950 setTimeout(function(){document.body.removeChild(frame);}, 100);
11953 Roo.EventManager.on(frame, 'load', cb, this);
11956 if(hiddens){ // remove dynamic params
11957 for(var i = 0, len = hiddens.length; i < len; i++){
11958 form.removeChild(hiddens[i]);
11962 // this is a 'formdata version???'
11965 doFormDataUpload : function(o, url)
11969 var form = Roo.getDom(o.form);
11970 form.enctype = form.encoding = 'multipart/form-data';
11971 formData = o.formData === true ? new FormData(form) : o.formData;
11973 formData = o.formData === true ? new FormData() : o.formData;
11978 success: this.handleResponse,
11979 failure: this.handleFailure,
11981 argument: {options: o},
11982 timeout : o.timeout || this.timeout
11985 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11989 }else if(this.autoAbort !== false){
11993 //Roo.lib.Ajax.defaultPostHeader = null;
11994 Roo.lib.Ajax.useDefaultHeader = false;
11995 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11996 Roo.lib.Ajax.useDefaultHeader = true;
12004 * Ext JS Library 1.1.1
12005 * Copyright(c) 2006-2007, Ext JS, LLC.
12007 * Originally Released Under LGPL - original licence link has changed is not relivant.
12010 * <script type="text/javascript">
12014 * Global Ajax request class.
12017 * @extends Roo.data.Connection
12020 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
12021 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12022 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
12023 * @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)
12024 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12025 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12026 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12028 Roo.Ajax = new Roo.data.Connection({
12037 * Serialize the passed form into a url encoded string
12039 * @param {String/HTMLElement} form
12042 serializeForm : function(form){
12043 return Roo.lib.Ajax.serializeForm(form);
12047 * Ext JS Library 1.1.1
12048 * Copyright(c) 2006-2007, Ext JS, LLC.
12050 * Originally Released Under LGPL - original licence link has changed is not relivant.
12053 * <script type="text/javascript">
12058 * @class Roo.UpdateManager
12059 * @extends Roo.util.Observable
12060 * Provides AJAX-style update for Element object.<br><br>
12063 * // Get it from a Roo.Element object
12064 * var el = Roo.get("foo");
12065 * var mgr = el.getUpdateManager();
12066 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
12068 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12070 * // or directly (returns the same UpdateManager instance)
12071 * var mgr = new Roo.UpdateManager("myElementId");
12072 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12073 * mgr.on("update", myFcnNeedsToKnow);
12075 // short handed call directly from the element object
12076 Roo.get("foo").load({
12080 text: "Loading Foo..."
12084 * Create new UpdateManager directly.
12085 * @param {String/HTMLElement/Roo.Element} el The element to update
12086 * @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).
12088 Roo.UpdateManager = function(el, forceNew){
12090 if(!forceNew && el.updateManager){
12091 return el.updateManager;
12094 * The Element object
12095 * @type Roo.Element
12099 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12102 this.defaultUrl = null;
12106 * @event beforeupdate
12107 * Fired before an update is made, return false from your handler and the update is cancelled.
12108 * @param {Roo.Element} el
12109 * @param {String/Object/Function} url
12110 * @param {String/Object} params
12112 "beforeupdate": true,
12115 * Fired after successful update is made.
12116 * @param {Roo.Element} el
12117 * @param {Object} oResponseObject The response Object
12122 * Fired on update failure.
12123 * @param {Roo.Element} el
12124 * @param {Object} oResponseObject The response Object
12128 var d = Roo.UpdateManager.defaults;
12130 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12133 this.sslBlankUrl = d.sslBlankUrl;
12135 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12138 this.disableCaching = d.disableCaching;
12140 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12143 this.indicatorText = d.indicatorText;
12145 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12148 this.showLoadIndicator = d.showLoadIndicator;
12150 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12153 this.timeout = d.timeout;
12156 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12159 this.loadScripts = d.loadScripts;
12162 * Transaction object of current executing transaction
12164 this.transaction = null;
12169 this.autoRefreshProcId = null;
12171 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12174 this.refreshDelegate = this.refresh.createDelegate(this);
12176 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12179 this.updateDelegate = this.update.createDelegate(this);
12181 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12184 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12188 this.successDelegate = this.processSuccess.createDelegate(this);
12192 this.failureDelegate = this.processFailure.createDelegate(this);
12194 if(!this.renderer){
12196 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12198 this.renderer = new Roo.UpdateManager.BasicRenderer();
12201 Roo.UpdateManager.superclass.constructor.call(this);
12204 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12206 * Get the Element this UpdateManager is bound to
12207 * @return {Roo.Element} The element
12209 getEl : function(){
12213 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12214 * @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:
12217 url: "your-url.php",<br/>
12218 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12219 callback: yourFunction,<br/>
12220 scope: yourObject, //(optional scope) <br/>
12221 discardUrl: false, <br/>
12222 nocache: false,<br/>
12223 text: "Loading...",<br/>
12225 scripts: false<br/>
12228 * The only required property is url. The optional properties nocache, text and scripts
12229 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12230 * @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}
12231 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12232 * @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.
12234 update : function(url, params, callback, discardUrl){
12235 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12236 var method = this.method,
12238 if(typeof url == "object"){ // must be config object
12241 params = params || cfg.params;
12242 callback = callback || cfg.callback;
12243 discardUrl = discardUrl || cfg.discardUrl;
12244 if(callback && cfg.scope){
12245 callback = callback.createDelegate(cfg.scope);
12247 if(typeof cfg.method != "undefined"){method = cfg.method;};
12248 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12249 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12250 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12251 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12253 this.showLoading();
12255 this.defaultUrl = url;
12257 if(typeof url == "function"){
12258 url = url.call(this);
12261 method = method || (params ? "POST" : "GET");
12262 if(method == "GET"){
12263 url = this.prepareUrl(url);
12266 var o = Roo.apply(cfg ||{}, {
12269 success: this.successDelegate,
12270 failure: this.failureDelegate,
12271 callback: undefined,
12272 timeout: (this.timeout*1000),
12273 argument: {"url": url, "form": null, "callback": callback, "params": params}
12275 Roo.log("updated manager called with timeout of " + o.timeout);
12276 this.transaction = Roo.Ajax.request(o);
12281 * 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.
12282 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12283 * @param {String/HTMLElement} form The form Id or form element
12284 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12285 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12286 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12288 formUpdate : function(form, url, reset, callback){
12289 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12290 if(typeof url == "function"){
12291 url = url.call(this);
12293 form = Roo.getDom(form);
12294 this.transaction = Roo.Ajax.request({
12297 success: this.successDelegate,
12298 failure: this.failureDelegate,
12299 timeout: (this.timeout*1000),
12300 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12302 this.showLoading.defer(1, this);
12307 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12308 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12310 refresh : function(callback){
12311 if(this.defaultUrl == null){
12314 this.update(this.defaultUrl, null, callback, true);
12318 * Set this element to auto refresh.
12319 * @param {Number} interval How often to update (in seconds).
12320 * @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)
12321 * @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}
12322 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12323 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12325 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12327 this.update(url || this.defaultUrl, params, callback, true);
12329 if(this.autoRefreshProcId){
12330 clearInterval(this.autoRefreshProcId);
12332 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12336 * Stop auto refresh on this element.
12338 stopAutoRefresh : function(){
12339 if(this.autoRefreshProcId){
12340 clearInterval(this.autoRefreshProcId);
12341 delete this.autoRefreshProcId;
12345 isAutoRefreshing : function(){
12346 return this.autoRefreshProcId ? true : false;
12349 * Called to update the element to "Loading" state. Override to perform custom action.
12351 showLoading : function(){
12352 if(this.showLoadIndicator){
12353 this.el.update(this.indicatorText);
12358 * Adds unique parameter to query string if disableCaching = true
12361 prepareUrl : function(url){
12362 if(this.disableCaching){
12363 var append = "_dc=" + (new Date().getTime());
12364 if(url.indexOf("?") !== -1){
12365 url += "&" + append;
12367 url += "?" + append;
12376 processSuccess : function(response){
12377 this.transaction = null;
12378 if(response.argument.form && response.argument.reset){
12379 try{ // put in try/catch since some older FF releases had problems with this
12380 response.argument.form.reset();
12383 if(this.loadScripts){
12384 this.renderer.render(this.el, response, this,
12385 this.updateComplete.createDelegate(this, [response]));
12387 this.renderer.render(this.el, response, this);
12388 this.updateComplete(response);
12392 updateComplete : function(response){
12393 this.fireEvent("update", this.el, response);
12394 if(typeof response.argument.callback == "function"){
12395 response.argument.callback(this.el, true, response);
12402 processFailure : function(response){
12403 this.transaction = null;
12404 this.fireEvent("failure", this.el, response);
12405 if(typeof response.argument.callback == "function"){
12406 response.argument.callback(this.el, false, response);
12411 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12412 * @param {Object} renderer The object implementing the render() method
12414 setRenderer : function(renderer){
12415 this.renderer = renderer;
12418 getRenderer : function(){
12419 return this.renderer;
12423 * Set the defaultUrl used for updates
12424 * @param {String/Function} defaultUrl The url or a function to call to get the url
12426 setDefaultUrl : function(defaultUrl){
12427 this.defaultUrl = defaultUrl;
12431 * Aborts the executing transaction
12433 abort : function(){
12434 if(this.transaction){
12435 Roo.Ajax.abort(this.transaction);
12440 * Returns true if an update is in progress
12441 * @return {Boolean}
12443 isUpdating : function(){
12444 if(this.transaction){
12445 return Roo.Ajax.isLoading(this.transaction);
12452 * @class Roo.UpdateManager.defaults
12453 * @static (not really - but it helps the doc tool)
12454 * The defaults collection enables customizing the default properties of UpdateManager
12456 Roo.UpdateManager.defaults = {
12458 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12464 * True to process scripts by default (Defaults to false).
12467 loadScripts : false,
12470 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12473 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12475 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12478 disableCaching : false,
12480 * Whether to show indicatorText when loading (Defaults to true).
12483 showLoadIndicator : true,
12485 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12488 indicatorText : '<div class="loading-indicator">Loading...</div>'
12492 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12494 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12495 * @param {String/HTMLElement/Roo.Element} el The element to update
12496 * @param {String} url The url
12497 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12498 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12501 * @member Roo.UpdateManager
12503 Roo.UpdateManager.updateElement = function(el, url, params, options){
12504 var um = Roo.get(el, true).getUpdateManager();
12505 Roo.apply(um, options);
12506 um.update(url, params, options ? options.callback : null);
12508 // alias for backwards compat
12509 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12511 * @class Roo.UpdateManager.BasicRenderer
12512 * Default Content renderer. Updates the elements innerHTML with the responseText.
12514 Roo.UpdateManager.BasicRenderer = function(){};
12516 Roo.UpdateManager.BasicRenderer.prototype = {
12518 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12519 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12520 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12521 * @param {Roo.Element} el The element being rendered
12522 * @param {Object} response The YUI Connect response object
12523 * @param {UpdateManager} updateManager The calling update manager
12524 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12526 render : function(el, response, updateManager, callback){
12527 el.update(response.responseText, updateManager.loadScripts, callback);
12533 * (c)) Alan Knowles
12539 * @class Roo.DomTemplate
12540 * @extends Roo.Template
12541 * An effort at a dom based template engine..
12543 * Similar to XTemplate, except it uses dom parsing to create the template..
12545 * Supported features:
12550 {a_variable} - output encoded.
12551 {a_variable.format:("Y-m-d")} - call a method on the variable
12552 {a_variable:raw} - unencoded output
12553 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12554 {a_variable:this.method_on_template(...)} - call a method on the template object.
12559 <div roo-for="a_variable or condition.."></div>
12560 <div roo-if="a_variable or condition"></div>
12561 <div roo-exec="some javascript"></div>
12562 <div roo-name="named_template"></div>
12567 Roo.DomTemplate = function()
12569 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12576 Roo.extend(Roo.DomTemplate, Roo.Template, {
12578 * id counter for sub templates.
12582 * flag to indicate if dom parser is inside a pre,
12583 * it will strip whitespace if not.
12588 * The various sub templates
12596 * basic tag replacing syntax
12599 * // you can fake an object call by doing this
12603 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12604 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12606 iterChild : function (node, method) {
12608 var oldPre = this.inPre;
12609 if (node.tagName == 'PRE') {
12612 for( var i = 0; i < node.childNodes.length; i++) {
12613 method.call(this, node.childNodes[i]);
12615 this.inPre = oldPre;
12621 * compile the template
12623 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12626 compile: function()
12630 // covert the html into DOM...
12634 doc = document.implementation.createHTMLDocument("");
12635 doc.documentElement.innerHTML = this.html ;
12636 div = doc.documentElement;
12638 // old IE... - nasty -- it causes all sorts of issues.. with
12639 // images getting pulled from server..
12640 div = document.createElement('div');
12641 div.innerHTML = this.html;
12643 //doc.documentElement.innerHTML = htmlBody
12649 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12651 var tpls = this.tpls;
12653 // create a top level template from the snippet..
12655 //Roo.log(div.innerHTML);
12662 body : div.innerHTML,
12675 Roo.each(tpls, function(tp){
12676 this.compileTpl(tp);
12677 this.tpls[tp.id] = tp;
12680 this.master = tpls[0];
12686 compileNode : function(node, istop) {
12691 // skip anything not a tag..
12692 if (node.nodeType != 1) {
12693 if (node.nodeType == 3 && !this.inPre) {
12694 // reduce white space..
12695 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12718 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12719 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12720 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12721 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12727 // just itterate children..
12728 this.iterChild(node,this.compileNode);
12731 tpl.uid = this.id++;
12732 tpl.value = node.getAttribute('roo-' + tpl.attr);
12733 node.removeAttribute('roo-'+ tpl.attr);
12734 if (tpl.attr != 'name') {
12735 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12736 node.parentNode.replaceChild(placeholder, node);
12739 var placeholder = document.createElement('span');
12740 placeholder.className = 'roo-tpl-' + tpl.value;
12741 node.parentNode.replaceChild(placeholder, node);
12744 // parent now sees '{domtplXXXX}
12745 this.iterChild(node,this.compileNode);
12747 // we should now have node body...
12748 var div = document.createElement('div');
12749 div.appendChild(node);
12751 // this has the unfortunate side effect of converting tagged attributes
12752 // eg. href="{...}" into %7C...%7D
12753 // this has been fixed by searching for those combo's although it's a bit hacky..
12756 tpl.body = div.innerHTML;
12763 switch (tpl.value) {
12764 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12765 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12766 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12771 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12775 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12779 tpl.id = tpl.value; // replace non characters???
12785 this.tpls.push(tpl);
12795 * Compile a segment of the template into a 'sub-template'
12801 compileTpl : function(tpl)
12803 var fm = Roo.util.Format;
12804 var useF = this.disableFormats !== true;
12806 var sep = Roo.isGecko ? "+\n" : ",\n";
12808 var undef = function(str) {
12809 Roo.debug && Roo.log("Property not found :" + str);
12813 //Roo.log(tpl.body);
12817 var fn = function(m, lbrace, name, format, args)
12820 //Roo.log(arguments);
12821 args = args ? args.replace(/\\'/g,"'") : args;
12822 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12823 if (typeof(format) == 'undefined') {
12824 format = 'htmlEncode';
12826 if (format == 'raw' ) {
12830 if(name.substr(0, 6) == 'domtpl'){
12831 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12834 // build an array of options to determine if value is undefined..
12836 // basically get 'xxxx.yyyy' then do
12837 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12838 // (function () { Roo.log("Property not found"); return ''; })() :
12843 Roo.each(name.split('.'), function(st) {
12844 lookfor += (lookfor.length ? '.': '') + st;
12845 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12848 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12851 if(format && useF){
12853 args = args ? ',' + args : "";
12855 if(format.substr(0, 5) != "this."){
12856 format = "fm." + format + '(';
12858 format = 'this.call("'+ format.substr(5) + '", ';
12862 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12865 if (args && args.length) {
12866 // called with xxyx.yuu:(test,test)
12868 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12870 // raw.. - :raw modifier..
12871 return "'"+ sep + udef_st + name + ")"+sep+"'";
12875 // branched to use + in gecko and [].join() in others
12877 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12878 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12881 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12882 body.push(tpl.body.replace(/(\r\n|\n)/g,
12883 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12884 body.push("'].join('');};};");
12885 body = body.join('');
12888 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12890 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12897 * same as applyTemplate, except it's done to one of the subTemplates
12898 * when using named templates, you can do:
12900 * var str = pl.applySubTemplate('your-name', values);
12903 * @param {Number} id of the template
12904 * @param {Object} values to apply to template
12905 * @param {Object} parent (normaly the instance of this object)
12907 applySubTemplate : function(id, values, parent)
12911 var t = this.tpls[id];
12915 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12916 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12920 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12927 if(t.execCall && t.execCall.call(this, values, parent)){
12931 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12937 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12938 parent = t.target ? values : parent;
12939 if(t.forCall && vs instanceof Array){
12941 for(var i = 0, len = vs.length; i < len; i++){
12943 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12945 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12947 //Roo.log(t.compiled);
12951 return buf.join('');
12954 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12959 return t.compiled.call(this, vs, parent);
12961 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12963 //Roo.log(t.compiled);
12971 applyTemplate : function(values){
12972 return this.master.compiled.call(this, values, {});
12973 //var s = this.subs;
12976 apply : function(){
12977 return this.applyTemplate.apply(this, arguments);
12982 Roo.DomTemplate.from = function(el){
12983 el = Roo.getDom(el);
12984 return new Roo.Domtemplate(el.value || el.innerHTML);
12987 * Ext JS Library 1.1.1
12988 * Copyright(c) 2006-2007, Ext JS, LLC.
12990 * Originally Released Under LGPL - original licence link has changed is not relivant.
12993 * <script type="text/javascript">
12997 * @class Roo.util.DelayedTask
12998 * Provides a convenient method of performing setTimeout where a new
12999 * timeout cancels the old timeout. An example would be performing validation on a keypress.
13000 * You can use this class to buffer
13001 * the keypress events for a certain number of milliseconds, and perform only if they stop
13002 * for that amount of time.
13003 * @constructor The parameters to this constructor serve as defaults and are not required.
13004 * @param {Function} fn (optional) The default function to timeout
13005 * @param {Object} scope (optional) The default scope of that timeout
13006 * @param {Array} args (optional) The default Array of arguments
13008 Roo.util.DelayedTask = function(fn, scope, args){
13009 var id = null, d, t;
13011 var call = function(){
13012 var now = new Date().getTime();
13016 fn.apply(scope, args || []);
13020 * Cancels any pending timeout and queues a new one
13021 * @param {Number} delay The milliseconds to delay
13022 * @param {Function} newFn (optional) Overrides function passed to constructor
13023 * @param {Object} newScope (optional) Overrides scope passed to constructor
13024 * @param {Array} newArgs (optional) Overrides args passed to constructor
13026 this.delay = function(delay, newFn, newScope, newArgs){
13027 if(id && delay != d){
13031 t = new Date().getTime();
13033 scope = newScope || scope;
13034 args = newArgs || args;
13036 id = setInterval(call, d);
13041 * Cancel the last queued timeout
13043 this.cancel = function(){
13051 * Ext JS Library 1.1.1
13052 * Copyright(c) 2006-2007, Ext JS, LLC.
13054 * Originally Released Under LGPL - original licence link has changed is not relivant.
13057 * <script type="text/javascript">
13061 Roo.util.TaskRunner = function(interval){
13062 interval = interval || 10;
13063 var tasks = [], removeQueue = [];
13065 var running = false;
13067 var stopThread = function(){
13073 var startThread = function(){
13076 id = setInterval(runTasks, interval);
13080 var removeTask = function(task){
13081 removeQueue.push(task);
13087 var runTasks = function(){
13088 if(removeQueue.length > 0){
13089 for(var i = 0, len = removeQueue.length; i < len; i++){
13090 tasks.remove(removeQueue[i]);
13093 if(tasks.length < 1){
13098 var now = new Date().getTime();
13099 for(var i = 0, len = tasks.length; i < len; ++i){
13101 var itime = now - t.taskRunTime;
13102 if(t.interval <= itime){
13103 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13104 t.taskRunTime = now;
13105 if(rt === false || t.taskRunCount === t.repeat){
13110 if(t.duration && t.duration <= (now - t.taskStartTime)){
13117 * Queues a new task.
13118 * @param {Object} task
13120 this.start = function(task){
13122 task.taskStartTime = new Date().getTime();
13123 task.taskRunTime = 0;
13124 task.taskRunCount = 0;
13129 this.stop = function(task){
13134 this.stopAll = function(){
13136 for(var i = 0, len = tasks.length; i < len; i++){
13137 if(tasks[i].onStop){
13146 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13148 * Ext JS Library 1.1.1
13149 * Copyright(c) 2006-2007, Ext JS, LLC.
13151 * Originally Released Under LGPL - original licence link has changed is not relivant.
13154 * <script type="text/javascript">
13159 * @class Roo.util.MixedCollection
13160 * @extends Roo.util.Observable
13161 * A Collection class that maintains both numeric indexes and keys and exposes events.
13163 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13164 * collection (defaults to false)
13165 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13166 * and return the key value for that item. This is used when available to look up the key on items that
13167 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13168 * equivalent to providing an implementation for the {@link #getKey} method.
13170 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13178 * Fires when the collection is cleared.
13183 * Fires when an item is added to the collection.
13184 * @param {Number} index The index at which the item was added.
13185 * @param {Object} o The item added.
13186 * @param {String} key The key associated with the added item.
13191 * Fires when an item is replaced in the collection.
13192 * @param {String} key he key associated with the new added.
13193 * @param {Object} old The item being replaced.
13194 * @param {Object} new The new item.
13199 * Fires when an item is removed from the collection.
13200 * @param {Object} o The item being removed.
13201 * @param {String} key (optional) The key associated with the removed item.
13206 this.allowFunctions = allowFunctions === true;
13208 this.getKey = keyFn;
13210 Roo.util.MixedCollection.superclass.constructor.call(this);
13213 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13214 allowFunctions : false,
13217 * Adds an item to the collection.
13218 * @param {String} key The key to associate with the item
13219 * @param {Object} o The item to add.
13220 * @return {Object} The item added.
13222 add : function(key, o){
13223 if(arguments.length == 1){
13225 key = this.getKey(o);
13227 if(typeof key == "undefined" || key === null){
13229 this.items.push(o);
13230 this.keys.push(null);
13232 var old = this.map[key];
13234 return this.replace(key, o);
13237 this.items.push(o);
13239 this.keys.push(key);
13241 this.fireEvent("add", this.length-1, o, key);
13246 * MixedCollection has a generic way to fetch keys if you implement getKey.
13249 var mc = new Roo.util.MixedCollection();
13250 mc.add(someEl.dom.id, someEl);
13251 mc.add(otherEl.dom.id, otherEl);
13255 var mc = new Roo.util.MixedCollection();
13256 mc.getKey = function(el){
13262 // or via the constructor
13263 var mc = new Roo.util.MixedCollection(false, function(el){
13269 * @param o {Object} The item for which to find the key.
13270 * @return {Object} The key for the passed item.
13272 getKey : function(o){
13277 * Replaces an item in the collection.
13278 * @param {String} key The key associated with the item to replace, or the item to replace.
13279 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13280 * @return {Object} The new item.
13282 replace : function(key, o){
13283 if(arguments.length == 1){
13285 key = this.getKey(o);
13287 var old = this.item(key);
13288 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13289 return this.add(key, o);
13291 var index = this.indexOfKey(key);
13292 this.items[index] = o;
13294 this.fireEvent("replace", key, old, o);
13299 * Adds all elements of an Array or an Object to the collection.
13300 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13301 * an Array of values, each of which are added to the collection.
13303 addAll : function(objs){
13304 if(arguments.length > 1 || objs instanceof Array){
13305 var args = arguments.length > 1 ? arguments : objs;
13306 for(var i = 0, len = args.length; i < len; i++){
13310 for(var key in objs){
13311 if(this.allowFunctions || typeof objs[key] != "function"){
13312 this.add(key, objs[key]);
13319 * Executes the specified function once for every item in the collection, passing each
13320 * item as the first and only parameter. returning false from the function will stop the iteration.
13321 * @param {Function} fn The function to execute for each item.
13322 * @param {Object} scope (optional) The scope in which to execute the function.
13324 each : function(fn, scope){
13325 var items = [].concat(this.items); // each safe for removal
13326 for(var i = 0, len = items.length; i < len; i++){
13327 if(fn.call(scope || items[i], items[i], i, len) === false){
13334 * Executes the specified function once for every key in the collection, passing each
13335 * key, and its associated item as the first two parameters.
13336 * @param {Function} fn The function to execute for each item.
13337 * @param {Object} scope (optional) The scope in which to execute the function.
13339 eachKey : function(fn, scope){
13340 for(var i = 0, len = this.keys.length; i < len; i++){
13341 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13346 * Returns the first item in the collection which elicits a true return value from the
13347 * passed selection function.
13348 * @param {Function} fn The selection function to execute for each item.
13349 * @param {Object} scope (optional) The scope in which to execute the function.
13350 * @return {Object} The first item in the collection which returned true from the selection function.
13352 find : function(fn, scope){
13353 for(var i = 0, len = this.items.length; i < len; i++){
13354 if(fn.call(scope || window, this.items[i], this.keys[i])){
13355 return this.items[i];
13362 * Inserts an item at the specified index in the collection.
13363 * @param {Number} index The index to insert the item at.
13364 * @param {String} key The key to associate with the new item, or the item itself.
13365 * @param {Object} o (optional) If the second parameter was a key, the new item.
13366 * @return {Object} The item inserted.
13368 insert : function(index, key, o){
13369 if(arguments.length == 2){
13371 key = this.getKey(o);
13373 if(index >= this.length){
13374 return this.add(key, o);
13377 this.items.splice(index, 0, o);
13378 if(typeof key != "undefined" && key != null){
13381 this.keys.splice(index, 0, key);
13382 this.fireEvent("add", index, o, key);
13387 * Removed an item from the collection.
13388 * @param {Object} o The item to remove.
13389 * @return {Object} The item removed.
13391 remove : function(o){
13392 return this.removeAt(this.indexOf(o));
13396 * Remove an item from a specified index in the collection.
13397 * @param {Number} index The index within the collection of the item to remove.
13399 removeAt : function(index){
13400 if(index < this.length && index >= 0){
13402 var o = this.items[index];
13403 this.items.splice(index, 1);
13404 var key = this.keys[index];
13405 if(typeof key != "undefined"){
13406 delete this.map[key];
13408 this.keys.splice(index, 1);
13409 this.fireEvent("remove", o, key);
13414 * Removed an item associated with the passed key fom the collection.
13415 * @param {String} key The key of the item to remove.
13417 removeKey : function(key){
13418 return this.removeAt(this.indexOfKey(key));
13422 * Returns the number of items in the collection.
13423 * @return {Number} the number of items in the collection.
13425 getCount : function(){
13426 return this.length;
13430 * Returns index within the collection of the passed Object.
13431 * @param {Object} o The item to find the index of.
13432 * @return {Number} index of the item.
13434 indexOf : function(o){
13435 if(!this.items.indexOf){
13436 for(var i = 0, len = this.items.length; i < len; i++){
13437 if(this.items[i] == o) {
13443 return this.items.indexOf(o);
13448 * Returns index within the collection of the passed key.
13449 * @param {String} key The key to find the index of.
13450 * @return {Number} index of the key.
13452 indexOfKey : function(key){
13453 if(!this.keys.indexOf){
13454 for(var i = 0, len = this.keys.length; i < len; i++){
13455 if(this.keys[i] == key) {
13461 return this.keys.indexOf(key);
13466 * Returns the item associated with the passed key OR index. Key has priority over index.
13467 * @param {String/Number} key The key or index of the item.
13468 * @return {Object} The item associated with the passed key.
13470 item : function(key){
13471 if (key === 'length') {
13474 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13475 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13479 * Returns the item at the specified index.
13480 * @param {Number} index The index of the item.
13483 itemAt : function(index){
13484 return this.items[index];
13488 * Returns the item associated with the passed key.
13489 * @param {String/Number} key The key of the item.
13490 * @return {Object} The item associated with the passed key.
13492 key : function(key){
13493 return this.map[key];
13497 * Returns true if the collection contains the passed Object as an item.
13498 * @param {Object} o The Object to look for in the collection.
13499 * @return {Boolean} True if the collection contains the Object as an item.
13501 contains : function(o){
13502 return this.indexOf(o) != -1;
13506 * Returns true if the collection contains the passed Object as a key.
13507 * @param {String} key The key to look for in the collection.
13508 * @return {Boolean} True if the collection contains the Object as a key.
13510 containsKey : function(key){
13511 return typeof this.map[key] != "undefined";
13515 * Removes all items from the collection.
13517 clear : function(){
13522 this.fireEvent("clear");
13526 * Returns the first item in the collection.
13527 * @return {Object} the first item in the collection..
13529 first : function(){
13530 return this.items[0];
13534 * Returns the last item in the collection.
13535 * @return {Object} the last item in the collection..
13538 return this.items[this.length-1];
13541 _sort : function(property, dir, fn){
13542 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13543 fn = fn || function(a, b){
13546 var c = [], k = this.keys, items = this.items;
13547 for(var i = 0, len = items.length; i < len; i++){
13548 c[c.length] = {key: k[i], value: items[i], index: i};
13550 c.sort(function(a, b){
13551 var v = fn(a[property], b[property]) * dsc;
13553 v = (a.index < b.index ? -1 : 1);
13557 for(var i = 0, len = c.length; i < len; i++){
13558 items[i] = c[i].value;
13561 this.fireEvent("sort", this);
13565 * Sorts this collection with the passed comparison function
13566 * @param {String} direction (optional) "ASC" or "DESC"
13567 * @param {Function} fn (optional) comparison function
13569 sort : function(dir, fn){
13570 this._sort("value", dir, fn);
13574 * Sorts this collection by keys
13575 * @param {String} direction (optional) "ASC" or "DESC"
13576 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13578 keySort : function(dir, fn){
13579 this._sort("key", dir, fn || function(a, b){
13580 return String(a).toUpperCase()-String(b).toUpperCase();
13585 * Returns a range of items in this collection
13586 * @param {Number} startIndex (optional) defaults to 0
13587 * @param {Number} endIndex (optional) default to the last item
13588 * @return {Array} An array of items
13590 getRange : function(start, end){
13591 var items = this.items;
13592 if(items.length < 1){
13595 start = start || 0;
13596 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13599 for(var i = start; i <= end; i++) {
13600 r[r.length] = items[i];
13603 for(var i = start; i >= end; i--) {
13604 r[r.length] = items[i];
13611 * Filter the <i>objects</i> in this collection by a specific property.
13612 * Returns a new collection that has been filtered.
13613 * @param {String} property A property on your objects
13614 * @param {String/RegExp} value Either string that the property values
13615 * should start with or a RegExp to test against the property
13616 * @return {MixedCollection} The new filtered collection
13618 filter : function(property, value){
13619 if(!value.exec){ // not a regex
13620 value = String(value);
13621 if(value.length == 0){
13622 return this.clone();
13624 value = new RegExp("^" + Roo.escapeRe(value), "i");
13626 return this.filterBy(function(o){
13627 return o && value.test(o[property]);
13632 * Filter by a function. * Returns a new collection that has been filtered.
13633 * The passed function will be called with each
13634 * object in the collection. If the function returns true, the value is included
13635 * otherwise it is filtered.
13636 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13637 * @param {Object} scope (optional) The scope of the function (defaults to this)
13638 * @return {MixedCollection} The new filtered collection
13640 filterBy : function(fn, scope){
13641 var r = new Roo.util.MixedCollection();
13642 r.getKey = this.getKey;
13643 var k = this.keys, it = this.items;
13644 for(var i = 0, len = it.length; i < len; i++){
13645 if(fn.call(scope||this, it[i], k[i])){
13646 r.add(k[i], it[i]);
13653 * Creates a duplicate of this collection
13654 * @return {MixedCollection}
13656 clone : function(){
13657 var r = new Roo.util.MixedCollection();
13658 var k = this.keys, it = this.items;
13659 for(var i = 0, len = it.length; i < len; i++){
13660 r.add(k[i], it[i]);
13662 r.getKey = this.getKey;
13667 * Returns the item associated with the passed key or index.
13669 * @param {String/Number} key The key or index of the item.
13670 * @return {Object} The item associated with the passed key.
13672 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13674 * Ext JS Library 1.1.1
13675 * Copyright(c) 2006-2007, Ext JS, LLC.
13677 * Originally Released Under LGPL - original licence link has changed is not relivant.
13680 * <script type="text/javascript">
13683 * @class Roo.util.JSON
13684 * Modified version of Douglas Crockford"s json.js that doesn"t
13685 * mess with the Object prototype
13686 * http://www.json.org/js.html
13689 Roo.util.JSON = new (function(){
13690 var useHasOwn = {}.hasOwnProperty ? true : false;
13692 // crashes Safari in some instances
13693 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13695 var pad = function(n) {
13696 return n < 10 ? "0" + n : n;
13709 var encodeString = function(s){
13710 if (/["\\\x00-\x1f]/.test(s)) {
13711 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13716 c = b.charCodeAt();
13718 Math.floor(c / 16).toString(16) +
13719 (c % 16).toString(16);
13722 return '"' + s + '"';
13725 var encodeArray = function(o){
13726 var a = ["["], b, i, l = o.length, v;
13727 for (i = 0; i < l; i += 1) {
13729 switch (typeof v) {
13738 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13746 var encodeDate = function(o){
13747 return '"' + o.getFullYear() + "-" +
13748 pad(o.getMonth() + 1) + "-" +
13749 pad(o.getDate()) + "T" +
13750 pad(o.getHours()) + ":" +
13751 pad(o.getMinutes()) + ":" +
13752 pad(o.getSeconds()) + '"';
13756 * Encodes an Object, Array or other value
13757 * @param {Mixed} o The variable to encode
13758 * @return {String} The JSON string
13760 this.encode = function(o)
13762 // should this be extended to fully wrap stringify..
13764 if(typeof o == "undefined" || o === null){
13766 }else if(o instanceof Array){
13767 return encodeArray(o);
13768 }else if(o instanceof Date){
13769 return encodeDate(o);
13770 }else if(typeof o == "string"){
13771 return encodeString(o);
13772 }else if(typeof o == "number"){
13773 return isFinite(o) ? String(o) : "null";
13774 }else if(typeof o == "boolean"){
13777 var a = ["{"], b, i, v;
13779 if(!useHasOwn || o.hasOwnProperty(i)) {
13781 switch (typeof v) {
13790 a.push(this.encode(i), ":",
13791 v === null ? "null" : this.encode(v));
13802 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13803 * @param {String} json The JSON string
13804 * @return {Object} The resulting object
13806 this.decode = function(json){
13808 return /** eval:var:json */ eval("(" + json + ')');
13812 * Shorthand for {@link Roo.util.JSON#encode}
13813 * @member Roo encode
13815 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13817 * Shorthand for {@link Roo.util.JSON#decode}
13818 * @member Roo decode
13820 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13823 * Ext JS Library 1.1.1
13824 * Copyright(c) 2006-2007, Ext JS, LLC.
13826 * Originally Released Under LGPL - original licence link has changed is not relivant.
13829 * <script type="text/javascript">
13833 * @class Roo.util.Format
13834 * Reusable data formatting functions
13837 Roo.util.Format = function(){
13838 var trimRe = /^\s+|\s+$/g;
13841 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13842 * @param {String} value The string to truncate
13843 * @param {Number} length The maximum length to allow before truncating
13844 * @return {String} The converted text
13846 ellipsis : function(value, len){
13847 if(value && value.length > len){
13848 return value.substr(0, len-3)+"...";
13854 * Checks a reference and converts it to empty string if it is undefined
13855 * @param {Mixed} value Reference to check
13856 * @return {Mixed} Empty string if converted, otherwise the original value
13858 undef : function(value){
13859 return typeof value != "undefined" ? value : "";
13863 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13864 * @param {String} value The string to encode
13865 * @return {String} The encoded text
13867 htmlEncode : function(value){
13868 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13872 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13873 * @param {String} value The string to decode
13874 * @return {String} The decoded text
13876 htmlDecode : function(value){
13877 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13881 * Trims any whitespace from either side of a string
13882 * @param {String} value The text to trim
13883 * @return {String} The trimmed text
13885 trim : function(value){
13886 return String(value).replace(trimRe, "");
13890 * Returns a substring from within an original string
13891 * @param {String} value The original text
13892 * @param {Number} start The start index of the substring
13893 * @param {Number} length The length of the substring
13894 * @return {String} The substring
13896 substr : function(value, start, length){
13897 return String(value).substr(start, length);
13901 * Converts a string to all lower case letters
13902 * @param {String} value The text to convert
13903 * @return {String} The converted text
13905 lowercase : function(value){
13906 return String(value).toLowerCase();
13910 * Converts a string to all upper case letters
13911 * @param {String} value The text to convert
13912 * @return {String} The converted text
13914 uppercase : function(value){
13915 return String(value).toUpperCase();
13919 * Converts the first character only of a string to upper case
13920 * @param {String} value The text to convert
13921 * @return {String} The converted text
13923 capitalize : function(value){
13924 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13928 call : function(value, fn){
13929 if(arguments.length > 2){
13930 var args = Array.prototype.slice.call(arguments, 2);
13931 args.unshift(value);
13933 return /** eval:var:value */ eval(fn).apply(window, args);
13935 /** eval:var:value */
13936 return /** eval:var:value */ eval(fn).call(window, value);
13942 * safer version of Math.toFixed..??/
13943 * @param {Number/String} value The numeric value to format
13944 * @param {Number/String} value Decimal places
13945 * @return {String} The formatted currency string
13947 toFixed : function(v, n)
13949 // why not use to fixed - precision is buggered???
13951 return Math.round(v-0);
13953 var fact = Math.pow(10,n+1);
13954 v = (Math.round((v-0)*fact))/fact;
13955 var z = (''+fact).substring(2);
13956 if (v == Math.floor(v)) {
13957 return Math.floor(v) + '.' + z;
13960 // now just padd decimals..
13961 var ps = String(v).split('.');
13962 var fd = (ps[1] + z);
13963 var r = fd.substring(0,n);
13964 var rm = fd.substring(n);
13966 return ps[0] + '.' + r;
13968 r*=1; // turn it into a number;
13970 if (String(r).length != n) {
13973 r = String(r).substring(1); // chop the end off.
13976 return ps[0] + '.' + r;
13981 * Format a number as US currency
13982 * @param {Number/String} value The numeric value to format
13983 * @return {String} The formatted currency string
13985 usMoney : function(v){
13986 return '$' + Roo.util.Format.number(v);
13991 * eventually this should probably emulate php's number_format
13992 * @param {Number/String} value The numeric value to format
13993 * @param {Number} decimals number of decimal places
13994 * @param {String} delimiter for thousands (default comma)
13995 * @return {String} The formatted currency string
13997 number : function(v, decimals, thousandsDelimiter)
13999 // multiply and round.
14000 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14001 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14003 var mul = Math.pow(10, decimals);
14004 var zero = String(mul).substring(1);
14005 v = (Math.round((v-0)*mul))/mul;
14007 // if it's '0' number.. then
14009 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14011 var ps = v.split('.');
14014 var r = /(\d+)(\d{3})/;
14017 if(thousandsDelimiter.length != 0) {
14018 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14023 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14024 // does not have decimals
14025 (decimals ? ('.' + zero) : '');
14028 return whole + sub ;
14032 * Parse a value into a formatted date using the specified format pattern.
14033 * @param {Mixed} value The value to format
14034 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14035 * @return {String} The formatted date string
14037 date : function(v, format){
14041 if(!(v instanceof Date)){
14042 v = new Date(Date.parse(v));
14044 return v.dateFormat(format || Roo.util.Format.defaults.date);
14048 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14049 * @param {String} format Any valid date format string
14050 * @return {Function} The date formatting function
14052 dateRenderer : function(format){
14053 return function(v){
14054 return Roo.util.Format.date(v, format);
14059 stripTagsRE : /<\/?[^>]+>/gi,
14062 * Strips all HTML tags
14063 * @param {Mixed} value The text from which to strip tags
14064 * @return {String} The stripped text
14066 stripTags : function(v){
14067 return !v ? v : String(v).replace(this.stripTagsRE, "");
14071 * Size in Mb,Gb etc.
14072 * @param {Number} value The number to be formated
14073 * @param {number} decimals how many decimal places
14074 * @return {String} the formated string
14076 size : function(value, decimals)
14078 var sizes = ['b', 'k', 'M', 'G', 'T'];
14082 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14083 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
14090 Roo.util.Format.defaults = {
14094 * Ext JS Library 1.1.1
14095 * Copyright(c) 2006-2007, Ext JS, LLC.
14097 * Originally Released Under LGPL - original licence link has changed is not relivant.
14100 * <script type="text/javascript">
14107 * @class Roo.MasterTemplate
14108 * @extends Roo.Template
14109 * Provides a template that can have child templates. The syntax is:
14111 var t = new Roo.MasterTemplate(
14112 '<select name="{name}">',
14113 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14116 t.add('options', {value: 'foo', text: 'bar'});
14117 // or you can add multiple child elements in one shot
14118 t.addAll('options', [
14119 {value: 'foo', text: 'bar'},
14120 {value: 'foo2', text: 'bar2'},
14121 {value: 'foo3', text: 'bar3'}
14123 // then append, applying the master template values
14124 t.append('my-form', {name: 'my-select'});
14126 * A name attribute for the child template is not required if you have only one child
14127 * template or you want to refer to them by index.
14129 Roo.MasterTemplate = function(){
14130 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14131 this.originalHtml = this.html;
14133 var m, re = this.subTemplateRe;
14136 while(m = re.exec(this.html)){
14137 var name = m[1], content = m[2];
14142 tpl : new Roo.Template(content)
14145 st[name] = st[subIndex];
14147 st[subIndex].tpl.compile();
14148 st[subIndex].tpl.call = this.call.createDelegate(this);
14151 this.subCount = subIndex;
14154 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14156 * The regular expression used to match sub templates
14160 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14163 * Applies the passed values to a child template.
14164 * @param {String/Number} name (optional) The name or index of the child template
14165 * @param {Array/Object} values The values to be applied to the template
14166 * @return {MasterTemplate} this
14168 add : function(name, values){
14169 if(arguments.length == 1){
14170 values = arguments[0];
14173 var s = this.subs[name];
14174 s.buffer[s.buffer.length] = s.tpl.apply(values);
14179 * Applies all the passed values to a child template.
14180 * @param {String/Number} name (optional) The name or index of the child template
14181 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14182 * @param {Boolean} reset (optional) True to reset the template first
14183 * @return {MasterTemplate} this
14185 fill : function(name, values, reset){
14187 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14195 for(var i = 0, len = values.length; i < len; i++){
14196 this.add(name, values[i]);
14202 * Resets the template for reuse
14203 * @return {MasterTemplate} this
14205 reset : function(){
14207 for(var i = 0; i < this.subCount; i++){
14213 applyTemplate : function(values){
14215 var replaceIndex = -1;
14216 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14217 return s[++replaceIndex].buffer.join("");
14219 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14222 apply : function(){
14223 return this.applyTemplate.apply(this, arguments);
14226 compile : function(){return this;}
14230 * Alias for fill().
14233 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14235 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14236 * var tpl = Roo.MasterTemplate.from('element-id');
14237 * @param {String/HTMLElement} el
14238 * @param {Object} config
14241 Roo.MasterTemplate.from = function(el, config){
14242 el = Roo.getDom(el);
14243 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14246 * Ext JS Library 1.1.1
14247 * Copyright(c) 2006-2007, Ext JS, LLC.
14249 * Originally Released Under LGPL - original licence link has changed is not relivant.
14252 * <script type="text/javascript">
14257 * @class Roo.util.CSS
14258 * Utility class for manipulating CSS rules
14261 Roo.util.CSS = function(){
14263 var doc = document;
14265 var camelRe = /(-[a-z])/gi;
14266 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14270 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14271 * tag and appended to the HEAD of the document.
14272 * @param {String|Object} cssText The text containing the css rules
14273 * @param {String} id An id to add to the stylesheet for later removal
14274 * @return {StyleSheet}
14276 createStyleSheet : function(cssText, id){
14278 var head = doc.getElementsByTagName("head")[0];
14279 var nrules = doc.createElement("style");
14280 nrules.setAttribute("type", "text/css");
14282 nrules.setAttribute("id", id);
14284 if (typeof(cssText) != 'string') {
14285 // support object maps..
14286 // not sure if this a good idea..
14287 // perhaps it should be merged with the general css handling
14288 // and handle js style props.
14289 var cssTextNew = [];
14290 for(var n in cssText) {
14292 for(var k in cssText[n]) {
14293 citems.push( k + ' : ' +cssText[n][k] + ';' );
14295 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14298 cssText = cssTextNew.join("\n");
14304 head.appendChild(nrules);
14305 ss = nrules.styleSheet;
14306 ss.cssText = cssText;
14309 nrules.appendChild(doc.createTextNode(cssText));
14311 nrules.cssText = cssText;
14313 head.appendChild(nrules);
14314 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14316 this.cacheStyleSheet(ss);
14321 * Removes a style or link tag by id
14322 * @param {String} id The id of the tag
14324 removeStyleSheet : function(id){
14325 var existing = doc.getElementById(id);
14327 existing.parentNode.removeChild(existing);
14332 * Dynamically swaps an existing stylesheet reference for a new one
14333 * @param {String} id The id of an existing link tag to remove
14334 * @param {String} url The href of the new stylesheet to include
14336 swapStyleSheet : function(id, url){
14337 this.removeStyleSheet(id);
14338 var ss = doc.createElement("link");
14339 ss.setAttribute("rel", "stylesheet");
14340 ss.setAttribute("type", "text/css");
14341 ss.setAttribute("id", id);
14342 ss.setAttribute("href", url);
14343 doc.getElementsByTagName("head")[0].appendChild(ss);
14347 * Refresh the rule cache if you have dynamically added stylesheets
14348 * @return {Object} An object (hash) of rules indexed by selector
14350 refreshCache : function(){
14351 return this.getRules(true);
14355 cacheStyleSheet : function(stylesheet){
14359 try{// try catch for cross domain access issue
14360 var ssRules = stylesheet.cssRules || stylesheet.rules;
14361 for(var j = ssRules.length-1; j >= 0; --j){
14362 rules[ssRules[j].selectorText] = ssRules[j];
14368 * Gets all css rules for the document
14369 * @param {Boolean} refreshCache true to refresh the internal cache
14370 * @return {Object} An object (hash) of rules indexed by selector
14372 getRules : function(refreshCache){
14373 if(rules == null || refreshCache){
14375 var ds = doc.styleSheets;
14376 for(var i =0, len = ds.length; i < len; i++){
14378 this.cacheStyleSheet(ds[i]);
14386 * Gets an an individual CSS rule by selector(s)
14387 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14388 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14389 * @return {CSSRule} The CSS rule or null if one is not found
14391 getRule : function(selector, refreshCache){
14392 var rs = this.getRules(refreshCache);
14393 if(!(selector instanceof Array)){
14394 return rs[selector];
14396 for(var i = 0; i < selector.length; i++){
14397 if(rs[selector[i]]){
14398 return rs[selector[i]];
14406 * Updates a rule property
14407 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14408 * @param {String} property The css property
14409 * @param {String} value The new value for the property
14410 * @return {Boolean} true If a rule was found and updated
14412 updateRule : function(selector, property, value){
14413 if(!(selector instanceof Array)){
14414 var rule = this.getRule(selector);
14416 rule.style[property.replace(camelRe, camelFn)] = value;
14420 for(var i = 0; i < selector.length; i++){
14421 if(this.updateRule(selector[i], property, value)){
14431 * Ext JS Library 1.1.1
14432 * Copyright(c) 2006-2007, Ext JS, LLC.
14434 * Originally Released Under LGPL - original licence link has changed is not relivant.
14437 * <script type="text/javascript">
14443 * @class Roo.util.ClickRepeater
14444 * @extends Roo.util.Observable
14446 * A wrapper class which can be applied to any element. Fires a "click" event while the
14447 * mouse is pressed. The interval between firings may be specified in the config but
14448 * defaults to 10 milliseconds.
14450 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14452 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14453 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14454 * Similar to an autorepeat key delay.
14455 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14456 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14457 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14458 * "interval" and "delay" are ignored. "immediate" is honored.
14459 * @cfg {Boolean} preventDefault True to prevent the default click event
14460 * @cfg {Boolean} stopDefault True to stop the default click event
14463 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14464 * 2007-02-02 jvs Renamed to ClickRepeater
14465 * 2007-02-03 jvs Modifications for FF Mac and Safari
14468 * @param {String/HTMLElement/Element} el The element to listen on
14469 * @param {Object} config
14471 Roo.util.ClickRepeater = function(el, config)
14473 this.el = Roo.get(el);
14474 this.el.unselectable();
14476 Roo.apply(this, config);
14481 * Fires when the mouse button is depressed.
14482 * @param {Roo.util.ClickRepeater} this
14484 "mousedown" : true,
14487 * Fires on a specified interval during the time the element is pressed.
14488 * @param {Roo.util.ClickRepeater} this
14493 * Fires when the mouse key is released.
14494 * @param {Roo.util.ClickRepeater} this
14499 this.el.on("mousedown", this.handleMouseDown, this);
14500 if(this.preventDefault || this.stopDefault){
14501 this.el.on("click", function(e){
14502 if(this.preventDefault){
14503 e.preventDefault();
14505 if(this.stopDefault){
14511 // allow inline handler
14513 this.on("click", this.handler, this.scope || this);
14516 Roo.util.ClickRepeater.superclass.constructor.call(this);
14519 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14522 preventDefault : true,
14523 stopDefault : false,
14527 handleMouseDown : function(){
14528 clearTimeout(this.timer);
14530 if(this.pressClass){
14531 this.el.addClass(this.pressClass);
14533 this.mousedownTime = new Date();
14535 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14536 this.el.on("mouseout", this.handleMouseOut, this);
14538 this.fireEvent("mousedown", this);
14539 this.fireEvent("click", this);
14541 this.timer = this.click.defer(this.delay || this.interval, this);
14545 click : function(){
14546 this.fireEvent("click", this);
14547 this.timer = this.click.defer(this.getInterval(), this);
14551 getInterval: function(){
14552 if(!this.accelerate){
14553 return this.interval;
14555 var pressTime = this.mousedownTime.getElapsed();
14556 if(pressTime < 500){
14558 }else if(pressTime < 1700){
14560 }else if(pressTime < 2600){
14562 }else if(pressTime < 3500){
14564 }else if(pressTime < 4400){
14566 }else if(pressTime < 5300){
14568 }else if(pressTime < 6200){
14576 handleMouseOut : function(){
14577 clearTimeout(this.timer);
14578 if(this.pressClass){
14579 this.el.removeClass(this.pressClass);
14581 this.el.on("mouseover", this.handleMouseReturn, this);
14585 handleMouseReturn : function(){
14586 this.el.un("mouseover", this.handleMouseReturn);
14587 if(this.pressClass){
14588 this.el.addClass(this.pressClass);
14594 handleMouseUp : function(){
14595 clearTimeout(this.timer);
14596 this.el.un("mouseover", this.handleMouseReturn);
14597 this.el.un("mouseout", this.handleMouseOut);
14598 Roo.get(document).un("mouseup", this.handleMouseUp);
14599 this.el.removeClass(this.pressClass);
14600 this.fireEvent("mouseup", this);
14603 * @class Roo.util.Clipboard
14609 Roo.util.Clipboard = {
14611 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
14612 * @param {String} text to copy to clipboard
14614 write : function(text) {
14615 // navigator clipboard api needs a secure context (https)
14616 if (navigator.clipboard && window.isSecureContext) {
14617 // navigator clipboard api method'
14618 navigator.clipboard.writeText(text);
14621 // text area method
14622 var ta = document.createElement("textarea");
14624 // make the textarea out of viewport
14625 ta.style.position = "fixed";
14626 ta.style.left = "-999999px";
14627 ta.style.top = "-999999px";
14628 document.body.appendChild(ta);
14631 document.execCommand('copy');
14641 * Ext JS Library 1.1.1
14642 * Copyright(c) 2006-2007, Ext JS, LLC.
14644 * Originally Released Under LGPL - original licence link has changed is not relivant.
14647 * <script type="text/javascript">
14652 * @class Roo.KeyNav
14653 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14654 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14655 * way to implement custom navigation schemes for any UI component.</p>
14656 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14657 * pageUp, pageDown, del, home, end. Usage:</p>
14659 var nav = new Roo.KeyNav("my-element", {
14660 "left" : function(e){
14661 this.moveLeft(e.ctrlKey);
14663 "right" : function(e){
14664 this.moveRight(e.ctrlKey);
14666 "enter" : function(e){
14673 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14674 * @param {Object} config The config
14676 Roo.KeyNav = function(el, config){
14677 this.el = Roo.get(el);
14678 Roo.apply(this, config);
14679 if(!this.disabled){
14680 this.disabled = true;
14685 Roo.KeyNav.prototype = {
14687 * @cfg {Boolean} disabled
14688 * True to disable this KeyNav instance (defaults to false)
14692 * @cfg {String} defaultEventAction
14693 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14694 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14695 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14697 defaultEventAction: "stopEvent",
14699 * @cfg {Boolean} forceKeyDown
14700 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14701 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14702 * handle keydown instead of keypress.
14704 forceKeyDown : false,
14707 prepareEvent : function(e){
14708 var k = e.getKey();
14709 var h = this.keyToHandler[k];
14710 //if(h && this[h]){
14711 // e.stopPropagation();
14713 if(Roo.isSafari && h && k >= 37 && k <= 40){
14719 relay : function(e){
14720 var k = e.getKey();
14721 var h = this.keyToHandler[k];
14723 if(this.doRelay(e, this[h], h) !== true){
14724 e[this.defaultEventAction]();
14730 doRelay : function(e, h, hname){
14731 return h.call(this.scope || this, e);
14734 // possible handlers
14748 // quick lookup hash
14765 * Enable this KeyNav
14767 enable: function(){
14769 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14770 // the EventObject will normalize Safari automatically
14771 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14772 this.el.on("keydown", this.relay, this);
14774 this.el.on("keydown", this.prepareEvent, this);
14775 this.el.on("keypress", this.relay, this);
14777 this.disabled = false;
14782 * Disable this KeyNav
14784 disable: function(){
14785 if(!this.disabled){
14786 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14787 this.el.un("keydown", this.relay);
14789 this.el.un("keydown", this.prepareEvent);
14790 this.el.un("keypress", this.relay);
14792 this.disabled = true;
14797 * Ext JS Library 1.1.1
14798 * Copyright(c) 2006-2007, Ext JS, LLC.
14800 * Originally Released Under LGPL - original licence link has changed is not relivant.
14803 * <script type="text/javascript">
14808 * @class Roo.KeyMap
14809 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14810 * The constructor accepts the same config object as defined by {@link #addBinding}.
14811 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14812 * combination it will call the function with this signature (if the match is a multi-key
14813 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14814 * A KeyMap can also handle a string representation of keys.<br />
14817 // map one key by key code
14818 var map = new Roo.KeyMap("my-element", {
14819 key: 13, // or Roo.EventObject.ENTER
14824 // map multiple keys to one action by string
14825 var map = new Roo.KeyMap("my-element", {
14831 // map multiple keys to multiple actions by strings and array of codes
14832 var map = new Roo.KeyMap("my-element", [
14835 fn: function(){ alert("Return was pressed"); }
14838 fn: function(){ alert('a, b or c was pressed'); }
14843 fn: function(){ alert('Control + shift + tab was pressed.'); }
14847 * <b>Note: A KeyMap starts enabled</b>
14849 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14850 * @param {Object} config The config (see {@link #addBinding})
14851 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14853 Roo.KeyMap = function(el, config, eventName){
14854 this.el = Roo.get(el);
14855 this.eventName = eventName || "keydown";
14856 this.bindings = [];
14858 this.addBinding(config);
14863 Roo.KeyMap.prototype = {
14865 * True to stop the event from bubbling and prevent the default browser action if the
14866 * key was handled by the KeyMap (defaults to false)
14872 * Add a new binding to this KeyMap. The following config object properties are supported:
14874 Property Type Description
14875 ---------- --------------- ----------------------------------------------------------------------
14876 key String/Array A single keycode or an array of keycodes to handle
14877 shift Boolean True to handle key only when shift is pressed (defaults to false)
14878 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14879 alt Boolean True to handle key only when alt is pressed (defaults to false)
14880 fn Function The function to call when KeyMap finds the expected key combination
14881 scope Object The scope of the callback function
14887 var map = new Roo.KeyMap(document, {
14888 key: Roo.EventObject.ENTER,
14893 //Add a new binding to the existing KeyMap later
14901 * @param {Object/Array} config A single KeyMap config or an array of configs
14903 addBinding : function(config){
14904 if(config instanceof Array){
14905 for(var i = 0, len = config.length; i < len; i++){
14906 this.addBinding(config[i]);
14910 var keyCode = config.key,
14911 shift = config.shift,
14912 ctrl = config.ctrl,
14915 scope = config.scope;
14916 if(typeof keyCode == "string"){
14918 var keyString = keyCode.toUpperCase();
14919 for(var j = 0, len = keyString.length; j < len; j++){
14920 ks.push(keyString.charCodeAt(j));
14924 var keyArray = keyCode instanceof Array;
14925 var handler = function(e){
14926 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14927 var k = e.getKey();
14929 for(var i = 0, len = keyCode.length; i < len; i++){
14930 if(keyCode[i] == k){
14931 if(this.stopEvent){
14934 fn.call(scope || window, k, e);
14940 if(this.stopEvent){
14943 fn.call(scope || window, k, e);
14948 this.bindings.push(handler);
14952 * Shorthand for adding a single key listener
14953 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14954 * following options:
14955 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14956 * @param {Function} fn The function to call
14957 * @param {Object} scope (optional) The scope of the function
14959 on : function(key, fn, scope){
14960 var keyCode, shift, ctrl, alt;
14961 if(typeof key == "object" && !(key instanceof Array)){
14980 handleKeyDown : function(e){
14981 if(this.enabled){ //just in case
14982 var b = this.bindings;
14983 for(var i = 0, len = b.length; i < len; i++){
14984 b[i].call(this, e);
14990 * Returns true if this KeyMap is enabled
14991 * @return {Boolean}
14993 isEnabled : function(){
14994 return this.enabled;
14998 * Enables this KeyMap
15000 enable: function(){
15002 this.el.on(this.eventName, this.handleKeyDown, this);
15003 this.enabled = true;
15008 * Disable this KeyMap
15010 disable: function(){
15012 this.el.removeListener(this.eventName, this.handleKeyDown, this);
15013 this.enabled = false;
15018 * Ext JS Library 1.1.1
15019 * Copyright(c) 2006-2007, Ext JS, LLC.
15021 * Originally Released Under LGPL - original licence link has changed is not relivant.
15024 * <script type="text/javascript">
15029 * @class Roo.util.TextMetrics
15030 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15031 * wide, in pixels, a given block of text will be.
15034 Roo.util.TextMetrics = function(){
15038 * Measures the size of the specified text
15039 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15040 * that can affect the size of the rendered text
15041 * @param {String} text The text to measure
15042 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15043 * in order to accurately measure the text height
15044 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15046 measure : function(el, text, fixedWidth){
15048 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15051 shared.setFixedWidth(fixedWidth || 'auto');
15052 return shared.getSize(text);
15056 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
15057 * the overhead of multiple calls to initialize the style properties on each measurement.
15058 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15059 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15060 * in order to accurately measure the text height
15061 * @return {Roo.util.TextMetrics.Instance} instance The new instance
15063 createInstance : function(el, fixedWidth){
15064 return Roo.util.TextMetrics.Instance(el, fixedWidth);
15071 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
15072 var ml = new Roo.Element(document.createElement('div'));
15073 document.body.appendChild(ml.dom);
15074 ml.position('absolute');
15075 ml.setLeftTop(-1000, -1000);
15079 ml.setWidth(fixedWidth);
15084 * Returns the size of the specified text based on the internal element's style and width properties
15085 * @memberOf Roo.util.TextMetrics.Instance#
15086 * @param {String} text The text to measure
15087 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15089 getSize : function(text){
15091 var s = ml.getSize();
15097 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15098 * that can affect the size of the rendered text
15099 * @memberOf Roo.util.TextMetrics.Instance#
15100 * @param {String/HTMLElement} el The element, dom node or id
15102 bind : function(el){
15104 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15109 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15110 * to set a fixed width in order to accurately measure the text height.
15111 * @memberOf Roo.util.TextMetrics.Instance#
15112 * @param {Number} width The width to set on the element
15114 setFixedWidth : function(width){
15115 ml.setWidth(width);
15119 * Returns the measured width of the specified text
15120 * @memberOf Roo.util.TextMetrics.Instance#
15121 * @param {String} text The text to measure
15122 * @return {Number} width The width in pixels
15124 getWidth : function(text){
15125 ml.dom.style.width = 'auto';
15126 return this.getSize(text).width;
15130 * Returns the measured height of the specified text. For multiline text, be sure to call
15131 * {@link #setFixedWidth} if necessary.
15132 * @memberOf Roo.util.TextMetrics.Instance#
15133 * @param {String} text The text to measure
15134 * @return {Number} height The height in pixels
15136 getHeight : function(text){
15137 return this.getSize(text).height;
15141 instance.bind(bindTo);
15146 // backwards compat
15147 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15149 * Ext JS Library 1.1.1
15150 * Copyright(c) 2006-2007, Ext JS, LLC.
15152 * Originally Released Under LGPL - original licence link has changed is not relivant.
15155 * <script type="text/javascript">
15159 * @class Roo.state.Provider
15160 * Abstract base class for state provider implementations. This class provides methods
15161 * for encoding and decoding <b>typed</b> variables including dates and defines the
15162 * Provider interface.
15164 Roo.state.Provider = function(){
15166 * @event statechange
15167 * Fires when a state change occurs.
15168 * @param {Provider} this This state provider
15169 * @param {String} key The state key which was changed
15170 * @param {String} value The encoded value for the state
15173 "statechange": true
15176 Roo.state.Provider.superclass.constructor.call(this);
15178 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15180 * Returns the current value for a key
15181 * @param {String} name The key name
15182 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15183 * @return {Mixed} The state data
15185 get : function(name, defaultValue){
15186 return typeof this.state[name] == "undefined" ?
15187 defaultValue : this.state[name];
15191 * Clears a value from the state
15192 * @param {String} name The key name
15194 clear : function(name){
15195 delete this.state[name];
15196 this.fireEvent("statechange", this, name, null);
15200 * Sets the value for a key
15201 * @param {String} name The key name
15202 * @param {Mixed} value The value to set
15204 set : function(name, value){
15205 this.state[name] = value;
15206 this.fireEvent("statechange", this, name, value);
15210 * Decodes a string previously encoded with {@link #encodeValue}.
15211 * @param {String} value The value to decode
15212 * @return {Mixed} The decoded value
15214 decodeValue : function(cookie){
15215 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15216 var matches = re.exec(unescape(cookie));
15217 if(!matches || !matches[1]) {
15218 return; // non state cookie
15220 var type = matches[1];
15221 var v = matches[2];
15224 return parseFloat(v);
15226 return new Date(Date.parse(v));
15231 var values = v.split("^");
15232 for(var i = 0, len = values.length; i < len; i++){
15233 all.push(this.decodeValue(values[i]));
15238 var values = v.split("^");
15239 for(var i = 0, len = values.length; i < len; i++){
15240 var kv = values[i].split("=");
15241 all[kv[0]] = this.decodeValue(kv[1]);
15250 * Encodes a value including type information. Decode with {@link #decodeValue}.
15251 * @param {Mixed} value The value to encode
15252 * @return {String} The encoded value
15254 encodeValue : function(v){
15256 if(typeof v == "number"){
15258 }else if(typeof v == "boolean"){
15259 enc = "b:" + (v ? "1" : "0");
15260 }else if(v instanceof Date){
15261 enc = "d:" + v.toGMTString();
15262 }else if(v instanceof Array){
15264 for(var i = 0, len = v.length; i < len; i++){
15265 flat += this.encodeValue(v[i]);
15271 }else if(typeof v == "object"){
15274 if(typeof v[key] != "function"){
15275 flat += key + "=" + this.encodeValue(v[key]) + "^";
15278 enc = "o:" + flat.substring(0, flat.length-1);
15282 return escape(enc);
15288 * Ext JS Library 1.1.1
15289 * Copyright(c) 2006-2007, Ext JS, LLC.
15291 * Originally Released Under LGPL - original licence link has changed is not relivant.
15294 * <script type="text/javascript">
15297 * @class Roo.state.Manager
15298 * This is the global state manager. By default all components that are "state aware" check this class
15299 * for state information if you don't pass them a custom state provider. In order for this class
15300 * to be useful, it must be initialized with a provider when your application initializes.
15302 // in your initialization function
15304 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15306 // supposed you have a {@link Roo.BorderLayout}
15307 var layout = new Roo.BorderLayout(...);
15308 layout.restoreState();
15309 // or a {Roo.BasicDialog}
15310 var dialog = new Roo.BasicDialog(...);
15311 dialog.restoreState();
15315 Roo.state.Manager = function(){
15316 var provider = new Roo.state.Provider();
15320 * Configures the default state provider for your application
15321 * @param {Provider} stateProvider The state provider to set
15323 setProvider : function(stateProvider){
15324 provider = stateProvider;
15328 * Returns the current value for a key
15329 * @param {String} name The key name
15330 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15331 * @return {Mixed} The state data
15333 get : function(key, defaultValue){
15334 return provider.get(key, defaultValue);
15338 * Sets the value for a key
15339 * @param {String} name The key name
15340 * @param {Mixed} value The state data
15342 set : function(key, value){
15343 provider.set(key, value);
15347 * Clears a value from the state
15348 * @param {String} name The key name
15350 clear : function(key){
15351 provider.clear(key);
15355 * Gets the currently configured state provider
15356 * @return {Provider} The state provider
15358 getProvider : function(){
15365 * Ext JS Library 1.1.1
15366 * Copyright(c) 2006-2007, Ext JS, LLC.
15368 * Originally Released Under LGPL - original licence link has changed is not relivant.
15371 * <script type="text/javascript">
15374 * @class Roo.state.CookieProvider
15375 * @extends Roo.state.Provider
15376 * The default Provider implementation which saves state via cookies.
15379 var cp = new Roo.state.CookieProvider({
15381 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15382 domain: "roojs.com"
15384 Roo.state.Manager.setProvider(cp);
15386 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15387 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15388 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15389 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15390 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15391 * domain the page is running on including the 'www' like 'www.roojs.com')
15392 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15394 * Create a new CookieProvider
15395 * @param {Object} config The configuration object
15397 Roo.state.CookieProvider = function(config){
15398 Roo.state.CookieProvider.superclass.constructor.call(this);
15400 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15401 this.domain = null;
15402 this.secure = false;
15403 Roo.apply(this, config);
15404 this.state = this.readCookies();
15407 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15409 set : function(name, value){
15410 if(typeof value == "undefined" || value === null){
15414 this.setCookie(name, value);
15415 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15419 clear : function(name){
15420 this.clearCookie(name);
15421 Roo.state.CookieProvider.superclass.clear.call(this, name);
15425 readCookies : function(){
15427 var c = document.cookie + ";";
15428 var re = /\s?(.*?)=(.*?);/g;
15430 while((matches = re.exec(c)) != null){
15431 var name = matches[1];
15432 var value = matches[2];
15433 if(name && name.substring(0,3) == "ys-"){
15434 cookies[name.substr(3)] = this.decodeValue(value);
15441 setCookie : function(name, value){
15442 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15443 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15444 ((this.path == null) ? "" : ("; path=" + this.path)) +
15445 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15446 ((this.secure == true) ? "; secure" : "");
15450 clearCookie : function(name){
15451 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15452 ((this.path == null) ? "" : ("; path=" + this.path)) +
15453 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15454 ((this.secure == true) ? "; secure" : "");
15458 * Ext JS Library 1.1.1
15459 * Copyright(c) 2006-2007, Ext JS, LLC.
15461 * Originally Released Under LGPL - original licence link has changed is not relivant.
15464 * <script type="text/javascript">
15469 * @class Roo.ComponentMgr
15470 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15473 Roo.ComponentMgr = function(){
15474 var all = new Roo.util.MixedCollection();
15478 * Registers a component.
15479 * @param {Roo.Component} c The component
15481 register : function(c){
15486 * Unregisters a component.
15487 * @param {Roo.Component} c The component
15489 unregister : function(c){
15494 * Returns a component by id
15495 * @param {String} id The component id
15497 get : function(id){
15498 return all.get(id);
15502 * Registers a function that will be called when a specified component is added to ComponentMgr
15503 * @param {String} id The component id
15504 * @param {Funtction} fn The callback function
15505 * @param {Object} scope The scope of the callback
15507 onAvailable : function(id, fn, scope){
15508 all.on("add", function(index, o){
15510 fn.call(scope || o, o);
15511 all.un("add", fn, scope);
15518 * Ext JS Library 1.1.1
15519 * Copyright(c) 2006-2007, Ext JS, LLC.
15521 * Originally Released Under LGPL - original licence link has changed is not relivant.
15524 * <script type="text/javascript">
15528 * @class Roo.Component
15529 * @extends Roo.util.Observable
15530 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15531 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15532 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15533 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15534 * All visual components (widgets) that require rendering into a layout should subclass Component.
15536 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15537 * 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
15538 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15540 Roo.Component = function(config){
15541 config = config || {};
15542 if(config.tagName || config.dom || typeof config == "string"){ // element object
15543 config = {el: config, id: config.id || config};
15545 this.initialConfig = config;
15547 Roo.apply(this, config);
15551 * Fires after the component is disabled.
15552 * @param {Roo.Component} this
15557 * Fires after the component is enabled.
15558 * @param {Roo.Component} this
15562 * @event beforeshow
15563 * Fires before the component is shown. Return false to stop the show.
15564 * @param {Roo.Component} this
15569 * Fires after the component is shown.
15570 * @param {Roo.Component} this
15574 * @event beforehide
15575 * Fires before the component is hidden. Return false to stop the hide.
15576 * @param {Roo.Component} this
15581 * Fires after the component is hidden.
15582 * @param {Roo.Component} this
15586 * @event beforerender
15587 * Fires before the component is rendered. Return false to stop the render.
15588 * @param {Roo.Component} this
15590 beforerender : true,
15593 * Fires after the component is rendered.
15594 * @param {Roo.Component} this
15598 * @event beforedestroy
15599 * Fires before the component is destroyed. Return false to stop the destroy.
15600 * @param {Roo.Component} this
15602 beforedestroy : true,
15605 * Fires after the component is destroyed.
15606 * @param {Roo.Component} this
15611 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15613 Roo.ComponentMgr.register(this);
15614 Roo.Component.superclass.constructor.call(this);
15615 this.initComponent();
15616 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15617 this.render(this.renderTo);
15618 delete this.renderTo;
15623 Roo.Component.AUTO_ID = 1000;
15625 Roo.extend(Roo.Component, Roo.util.Observable, {
15627 * @scope Roo.Component.prototype
15629 * true if this component is hidden. Read-only.
15634 * true if this component is disabled. Read-only.
15639 * true if this component has been rendered. Read-only.
15643 /** @cfg {String} disableClass
15644 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15646 disabledClass : "x-item-disabled",
15647 /** @cfg {Boolean} allowDomMove
15648 * Whether the component can move the Dom node when rendering (defaults to true).
15650 allowDomMove : true,
15651 /** @cfg {String} hideMode (display|visibility)
15652 * How this component should hidden. Supported values are
15653 * "visibility" (css visibility), "offsets" (negative offset position) and
15654 * "display" (css display) - defaults to "display".
15656 hideMode: 'display',
15659 ctype : "Roo.Component",
15662 * @cfg {String} actionMode
15663 * which property holds the element that used for hide() / show() / disable() / enable()
15664 * default is 'el' for forms you probably want to set this to fieldEl
15669 getActionEl : function(){
15670 return this[this.actionMode];
15673 initComponent : Roo.emptyFn,
15675 * If this is a lazy rendering component, render it to its container element.
15676 * @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.
15678 render : function(container, position){
15684 if(this.fireEvent("beforerender", this) === false){
15688 if(!container && this.el){
15689 this.el = Roo.get(this.el);
15690 container = this.el.dom.parentNode;
15691 this.allowDomMove = false;
15693 this.container = Roo.get(container);
15694 this.rendered = true;
15695 if(position !== undefined){
15696 if(typeof position == 'number'){
15697 position = this.container.dom.childNodes[position];
15699 position = Roo.getDom(position);
15702 this.onRender(this.container, position || null);
15704 this.el.addClass(this.cls);
15708 this.el.applyStyles(this.style);
15711 this.fireEvent("render", this);
15712 this.afterRender(this.container);
15725 // default function is not really useful
15726 onRender : function(ct, position){
15728 this.el = Roo.get(this.el);
15729 if(this.allowDomMove !== false){
15730 ct.dom.insertBefore(this.el.dom, position);
15736 getAutoCreate : function(){
15737 var cfg = typeof this.autoCreate == "object" ?
15738 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15739 if(this.id && !cfg.id){
15746 afterRender : Roo.emptyFn,
15749 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15750 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15752 destroy : function(){
15753 if(this.fireEvent("beforedestroy", this) !== false){
15754 this.purgeListeners();
15755 this.beforeDestroy();
15757 this.el.removeAllListeners();
15759 if(this.actionMode == "container"){
15760 this.container.remove();
15764 Roo.ComponentMgr.unregister(this);
15765 this.fireEvent("destroy", this);
15770 beforeDestroy : function(){
15775 onDestroy : function(){
15780 * Returns the underlying {@link Roo.Element}.
15781 * @return {Roo.Element} The element
15783 getEl : function(){
15788 * Returns the id of this component.
15791 getId : function(){
15796 * Try to focus this component.
15797 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15798 * @return {Roo.Component} this
15800 focus : function(selectText){
15803 if(selectText === true){
15804 this.el.dom.select();
15819 * Disable this component.
15820 * @return {Roo.Component} this
15822 disable : function(){
15826 this.disabled = true;
15827 this.fireEvent("disable", this);
15832 onDisable : function(){
15833 this.getActionEl().addClass(this.disabledClass);
15834 this.el.dom.disabled = true;
15838 * Enable this component.
15839 * @return {Roo.Component} this
15841 enable : function(){
15845 this.disabled = false;
15846 this.fireEvent("enable", this);
15851 onEnable : function(){
15852 this.getActionEl().removeClass(this.disabledClass);
15853 this.el.dom.disabled = false;
15857 * Convenience function for setting disabled/enabled by boolean.
15858 * @param {Boolean} disabled
15860 setDisabled : function(disabled){
15861 this[disabled ? "disable" : "enable"]();
15865 * Show this component.
15866 * @return {Roo.Component} this
15869 if(this.fireEvent("beforeshow", this) !== false){
15870 this.hidden = false;
15874 this.fireEvent("show", this);
15880 onShow : function(){
15881 var ae = this.getActionEl();
15882 if(this.hideMode == 'visibility'){
15883 ae.dom.style.visibility = "visible";
15884 }else if(this.hideMode == 'offsets'){
15885 ae.removeClass('x-hidden');
15887 ae.dom.style.display = "";
15892 * Hide this component.
15893 * @return {Roo.Component} this
15896 if(this.fireEvent("beforehide", this) !== false){
15897 this.hidden = true;
15901 this.fireEvent("hide", this);
15907 onHide : function(){
15908 var ae = this.getActionEl();
15909 if(this.hideMode == 'visibility'){
15910 ae.dom.style.visibility = "hidden";
15911 }else if(this.hideMode == 'offsets'){
15912 ae.addClass('x-hidden');
15914 ae.dom.style.display = "none";
15919 * Convenience function to hide or show this component by boolean.
15920 * @param {Boolean} visible True to show, false to hide
15921 * @return {Roo.Component} this
15923 setVisible: function(visible){
15933 * Returns true if this component is visible.
15935 isVisible : function(){
15936 return this.getActionEl().isVisible();
15939 cloneConfig : function(overrides){
15940 overrides = overrides || {};
15941 var id = overrides.id || Roo.id();
15942 var cfg = Roo.applyIf(overrides, this.initialConfig);
15943 cfg.id = id; // prevent dup id
15944 return new this.constructor(cfg);
15948 * Ext JS Library 1.1.1
15949 * Copyright(c) 2006-2007, Ext JS, LLC.
15951 * Originally Released Under LGPL - original licence link has changed is not relivant.
15954 * <script type="text/javascript">
15958 * @class Roo.BoxComponent
15959 * @extends Roo.Component
15960 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15961 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15962 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
15963 * layout containers.
15965 * @param {Roo.Element/String/Object} config The configuration options.
15967 Roo.BoxComponent = function(config){
15968 Roo.Component.call(this, config);
15972 * Fires after the component is resized.
15973 * @param {Roo.Component} this
15974 * @param {Number} adjWidth The box-adjusted width that was set
15975 * @param {Number} adjHeight The box-adjusted height that was set
15976 * @param {Number} rawWidth The width that was originally specified
15977 * @param {Number} rawHeight The height that was originally specified
15982 * Fires after the component is moved.
15983 * @param {Roo.Component} this
15984 * @param {Number} x The new x position
15985 * @param {Number} y The new y position
15991 Roo.extend(Roo.BoxComponent, Roo.Component, {
15992 // private, set in afterRender to signify that the component has been rendered
15994 // private, used to defer height settings to subclasses
15995 deferHeight: false,
15996 /** @cfg {Number} width
15997 * width (optional) size of component
15999 /** @cfg {Number} height
16000 * height (optional) size of component
16004 * Sets the width and height of the component. This method fires the resize event. This method can accept
16005 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16006 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16007 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16008 * @return {Roo.BoxComponent} this
16010 setSize : function(w, h){
16011 // support for standard size objects
16012 if(typeof w == 'object'){
16017 if(!this.boxReady){
16023 // prevent recalcs when not needed
16024 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16027 this.lastSize = {width: w, height: h};
16029 var adj = this.adjustSize(w, h);
16030 var aw = adj.width, ah = adj.height;
16031 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16032 var rz = this.getResizeEl();
16033 if(!this.deferHeight && aw !== undefined && ah !== undefined){
16034 rz.setSize(aw, ah);
16035 }else if(!this.deferHeight && ah !== undefined){
16037 }else if(aw !== undefined){
16040 this.onResize(aw, ah, w, h);
16041 this.fireEvent('resize', this, aw, ah, w, h);
16047 * Gets the current size of the component's underlying element.
16048 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16050 getSize : function(){
16051 return this.el.getSize();
16055 * Gets the current XY position of the component's underlying element.
16056 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16057 * @return {Array} The XY position of the element (e.g., [100, 200])
16059 getPosition : function(local){
16060 if(local === true){
16061 return [this.el.getLeft(true), this.el.getTop(true)];
16063 return this.xy || this.el.getXY();
16067 * Gets the current box measurements of the component's underlying element.
16068 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16069 * @returns {Object} box An object in the format {x, y, width, height}
16071 getBox : function(local){
16072 var s = this.el.getSize();
16074 s.x = this.el.getLeft(true);
16075 s.y = this.el.getTop(true);
16077 var xy = this.xy || this.el.getXY();
16085 * Sets the current box measurements of the component's underlying element.
16086 * @param {Object} box An object in the format {x, y, width, height}
16087 * @returns {Roo.BoxComponent} this
16089 updateBox : function(box){
16090 this.setSize(box.width, box.height);
16091 this.setPagePosition(box.x, box.y);
16096 getResizeEl : function(){
16097 return this.resizeEl || this.el;
16101 getPositionEl : function(){
16102 return this.positionEl || this.el;
16106 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16107 * This method fires the move event.
16108 * @param {Number} left The new left
16109 * @param {Number} top The new top
16110 * @returns {Roo.BoxComponent} this
16112 setPosition : function(x, y){
16115 if(!this.boxReady){
16118 var adj = this.adjustPosition(x, y);
16119 var ax = adj.x, ay = adj.y;
16121 var el = this.getPositionEl();
16122 if(ax !== undefined || ay !== undefined){
16123 if(ax !== undefined && ay !== undefined){
16124 el.setLeftTop(ax, ay);
16125 }else if(ax !== undefined){
16127 }else if(ay !== undefined){
16130 this.onPosition(ax, ay);
16131 this.fireEvent('move', this, ax, ay);
16137 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16138 * This method fires the move event.
16139 * @param {Number} x The new x position
16140 * @param {Number} y The new y position
16141 * @returns {Roo.BoxComponent} this
16143 setPagePosition : function(x, y){
16146 if(!this.boxReady){
16149 if(x === undefined || y === undefined){ // cannot translate undefined points
16152 var p = this.el.translatePoints(x, y);
16153 this.setPosition(p.left, p.top);
16158 onRender : function(ct, position){
16159 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16161 this.resizeEl = Roo.get(this.resizeEl);
16163 if(this.positionEl){
16164 this.positionEl = Roo.get(this.positionEl);
16169 afterRender : function(){
16170 Roo.BoxComponent.superclass.afterRender.call(this);
16171 this.boxReady = true;
16172 this.setSize(this.width, this.height);
16173 if(this.x || this.y){
16174 this.setPosition(this.x, this.y);
16176 if(this.pageX || this.pageY){
16177 this.setPagePosition(this.pageX, this.pageY);
16182 * Force the component's size to recalculate based on the underlying element's current height and width.
16183 * @returns {Roo.BoxComponent} this
16185 syncSize : function(){
16186 delete this.lastSize;
16187 this.setSize(this.el.getWidth(), this.el.getHeight());
16192 * Called after the component is resized, this method is empty by default but can be implemented by any
16193 * subclass that needs to perform custom logic after a resize occurs.
16194 * @param {Number} adjWidth The box-adjusted width that was set
16195 * @param {Number} adjHeight The box-adjusted height that was set
16196 * @param {Number} rawWidth The width that was originally specified
16197 * @param {Number} rawHeight The height that was originally specified
16199 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16204 * Called after the component is moved, this method is empty by default but can be implemented by any
16205 * subclass that needs to perform custom logic after a move occurs.
16206 * @param {Number} x The new x position
16207 * @param {Number} y The new y position
16209 onPosition : function(x, y){
16214 adjustSize : function(w, h){
16215 if(this.autoWidth){
16218 if(this.autoHeight){
16221 return {width : w, height: h};
16225 adjustPosition : function(x, y){
16226 return {x : x, y: y};
16230 * Ext JS Library 1.1.1
16231 * Copyright(c) 2006-2007, Ext JS, LLC.
16233 * Originally Released Under LGPL - original licence link has changed is not relivant.
16236 * <script type="text/javascript">
16241 * @extends Roo.Element
16242 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16243 * automatic maintaining of shadow/shim positions.
16244 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16245 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16246 * you can pass a string with a CSS class name. False turns off the shadow.
16247 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16248 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16249 * @cfg {String} cls CSS class to add to the element
16250 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16251 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16253 * @param {Object} config An object with config options.
16254 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16257 Roo.Layer = function(config, existingEl){
16258 config = config || {};
16259 var dh = Roo.DomHelper;
16260 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16262 this.dom = Roo.getDom(existingEl);
16265 var o = config.dh || {tag: "div", cls: "x-layer"};
16266 this.dom = dh.append(pel, o);
16269 this.addClass(config.cls);
16271 this.constrain = config.constrain !== false;
16272 this.visibilityMode = Roo.Element.VISIBILITY;
16274 this.id = this.dom.id = config.id;
16276 this.id = Roo.id(this.dom);
16278 this.zindex = config.zindex || this.getZIndex();
16279 this.position("absolute", this.zindex);
16281 this.shadowOffset = config.shadowOffset || 4;
16282 this.shadow = new Roo.Shadow({
16283 offset : this.shadowOffset,
16284 mode : config.shadow
16287 this.shadowOffset = 0;
16289 this.useShim = config.shim !== false && Roo.useShims;
16290 this.useDisplay = config.useDisplay;
16294 var supr = Roo.Element.prototype;
16296 // shims are shared among layer to keep from having 100 iframes
16299 Roo.extend(Roo.Layer, Roo.Element, {
16301 getZIndex : function(){
16302 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16305 getShim : function(){
16312 var shim = shims.shift();
16314 shim = this.createShim();
16315 shim.enableDisplayMode('block');
16316 shim.dom.style.display = 'none';
16317 shim.dom.style.visibility = 'visible';
16319 var pn = this.dom.parentNode;
16320 if(shim.dom.parentNode != pn){
16321 pn.insertBefore(shim.dom, this.dom);
16323 shim.setStyle('z-index', this.getZIndex()-2);
16328 hideShim : function(){
16330 this.shim.setDisplayed(false);
16331 shims.push(this.shim);
16336 disableShadow : function(){
16338 this.shadowDisabled = true;
16339 this.shadow.hide();
16340 this.lastShadowOffset = this.shadowOffset;
16341 this.shadowOffset = 0;
16345 enableShadow : function(show){
16347 this.shadowDisabled = false;
16348 this.shadowOffset = this.lastShadowOffset;
16349 delete this.lastShadowOffset;
16357 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16358 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16359 sync : function(doShow){
16360 var sw = this.shadow;
16361 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16362 var sh = this.getShim();
16364 var w = this.getWidth(),
16365 h = this.getHeight();
16367 var l = this.getLeft(true),
16368 t = this.getTop(true);
16370 if(sw && !this.shadowDisabled){
16371 if(doShow && !sw.isVisible()){
16374 sw.realign(l, t, w, h);
16380 // fit the shim behind the shadow, so it is shimmed too
16381 var a = sw.adjusts, s = sh.dom.style;
16382 s.left = (Math.min(l, l+a.l))+"px";
16383 s.top = (Math.min(t, t+a.t))+"px";
16384 s.width = (w+a.w)+"px";
16385 s.height = (h+a.h)+"px";
16392 sh.setLeftTop(l, t);
16399 destroy : function(){
16402 this.shadow.hide();
16404 this.removeAllListeners();
16405 var pn = this.dom.parentNode;
16407 pn.removeChild(this.dom);
16409 Roo.Element.uncache(this.id);
16412 remove : function(){
16417 beginUpdate : function(){
16418 this.updating = true;
16422 endUpdate : function(){
16423 this.updating = false;
16428 hideUnders : function(negOffset){
16430 this.shadow.hide();
16436 constrainXY : function(){
16437 if(this.constrain){
16438 var vw = Roo.lib.Dom.getViewWidth(),
16439 vh = Roo.lib.Dom.getViewHeight();
16440 var s = Roo.get(document).getScroll();
16442 var xy = this.getXY();
16443 var x = xy[0], y = xy[1];
16444 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16445 // only move it if it needs it
16447 // first validate right/bottom
16448 if((x + w) > vw+s.left){
16449 x = vw - w - this.shadowOffset;
16452 if((y + h) > vh+s.top){
16453 y = vh - h - this.shadowOffset;
16456 // then make sure top/left isn't negative
16467 var ay = this.avoidY;
16468 if(y <= ay && (y+h) >= ay){
16474 supr.setXY.call(this, xy);
16480 isVisible : function(){
16481 return this.visible;
16485 showAction : function(){
16486 this.visible = true; // track visibility to prevent getStyle calls
16487 if(this.useDisplay === true){
16488 this.setDisplayed("");
16489 }else if(this.lastXY){
16490 supr.setXY.call(this, this.lastXY);
16491 }else if(this.lastLT){
16492 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16497 hideAction : function(){
16498 this.visible = false;
16499 if(this.useDisplay === true){
16500 this.setDisplayed(false);
16502 this.setLeftTop(-10000,-10000);
16506 // overridden Element method
16507 setVisible : function(v, a, d, c, e){
16512 var cb = function(){
16517 }.createDelegate(this);
16518 supr.setVisible.call(this, true, true, d, cb, e);
16521 this.hideUnders(true);
16530 }.createDelegate(this);
16532 supr.setVisible.call(this, v, a, d, cb, e);
16541 storeXY : function(xy){
16542 delete this.lastLT;
16546 storeLeftTop : function(left, top){
16547 delete this.lastXY;
16548 this.lastLT = [left, top];
16552 beforeFx : function(){
16553 this.beforeAction();
16554 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16558 afterFx : function(){
16559 Roo.Layer.superclass.afterFx.apply(this, arguments);
16560 this.sync(this.isVisible());
16564 beforeAction : function(){
16565 if(!this.updating && this.shadow){
16566 this.shadow.hide();
16570 // overridden Element method
16571 setLeft : function(left){
16572 this.storeLeftTop(left, this.getTop(true));
16573 supr.setLeft.apply(this, arguments);
16577 setTop : function(top){
16578 this.storeLeftTop(this.getLeft(true), top);
16579 supr.setTop.apply(this, arguments);
16583 setLeftTop : function(left, top){
16584 this.storeLeftTop(left, top);
16585 supr.setLeftTop.apply(this, arguments);
16589 setXY : function(xy, a, d, c, e){
16591 this.beforeAction();
16593 var cb = this.createCB(c);
16594 supr.setXY.call(this, xy, a, d, cb, e);
16601 createCB : function(c){
16612 // overridden Element method
16613 setX : function(x, a, d, c, e){
16614 this.setXY([x, this.getY()], a, d, c, e);
16617 // overridden Element method
16618 setY : function(y, a, d, c, e){
16619 this.setXY([this.getX(), y], a, d, c, e);
16622 // overridden Element method
16623 setSize : function(w, h, a, d, c, e){
16624 this.beforeAction();
16625 var cb = this.createCB(c);
16626 supr.setSize.call(this, w, h, a, d, cb, e);
16632 // overridden Element method
16633 setWidth : function(w, a, d, c, e){
16634 this.beforeAction();
16635 var cb = this.createCB(c);
16636 supr.setWidth.call(this, w, a, d, cb, e);
16642 // overridden Element method
16643 setHeight : function(h, a, d, c, e){
16644 this.beforeAction();
16645 var cb = this.createCB(c);
16646 supr.setHeight.call(this, h, a, d, cb, e);
16652 // overridden Element method
16653 setBounds : function(x, y, w, h, a, d, c, e){
16654 this.beforeAction();
16655 var cb = this.createCB(c);
16657 this.storeXY([x, y]);
16658 supr.setXY.call(this, [x, y]);
16659 supr.setSize.call(this, w, h, a, d, cb, e);
16662 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16668 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16669 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16670 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16671 * @param {Number} zindex The new z-index to set
16672 * @return {this} The Layer
16674 setZIndex : function(zindex){
16675 this.zindex = zindex;
16676 this.setStyle("z-index", zindex + 2);
16678 this.shadow.setZIndex(zindex + 1);
16681 this.shim.setStyle("z-index", zindex);
16686 * Original code for Roojs - LGPL
16687 * <script type="text/javascript">
16691 * @class Roo.XComponent
16692 * A delayed Element creator...
16693 * Or a way to group chunks of interface together.
16694 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16695 * used in conjunction with XComponent.build() it will create an instance of each element,
16696 * then call addxtype() to build the User interface.
16698 * Mypart.xyx = new Roo.XComponent({
16700 parent : 'Mypart.xyz', // empty == document.element.!!
16704 disabled : function() {}
16706 tree : function() { // return an tree of xtype declared components
16710 xtype : 'NestedLayoutPanel',
16717 * It can be used to build a big heiracy, with parent etc.
16718 * or you can just use this to render a single compoent to a dom element
16719 * MYPART.render(Roo.Element | String(id) | dom_element )
16726 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16727 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16729 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16731 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16732 * - if mulitple topModules exist, the last one is defined as the top module.
16736 * When the top level or multiple modules are to embedded into a existing HTML page,
16737 * the parent element can container '#id' of the element where the module will be drawn.
16741 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16742 * it relies more on a include mechanism, where sub modules are included into an outer page.
16743 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16745 * Bootstrap Roo Included elements
16747 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16748 * hence confusing the component builder as it thinks there are multiple top level elements.
16750 * String Over-ride & Translations
16752 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16753 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16754 * are needed. @see Roo.XComponent.overlayString
16758 * @extends Roo.util.Observable
16760 * @param cfg {Object} configuration of component
16763 Roo.XComponent = function(cfg) {
16764 Roo.apply(this, cfg);
16768 * Fires when this the componnt is built
16769 * @param {Roo.XComponent} c the component
16774 this.region = this.region || 'center'; // default..
16775 Roo.XComponent.register(this);
16776 this.modules = false;
16777 this.el = false; // where the layout goes..
16781 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16784 * The created element (with Roo.factory())
16785 * @type {Roo.Layout}
16791 * for BC - use el in new code
16792 * @type {Roo.Layout}
16798 * for BC - use el in new code
16799 * @type {Roo.Layout}
16804 * @cfg {Function|boolean} disabled
16805 * If this module is disabled by some rule, return true from the funtion
16810 * @cfg {String} parent
16811 * Name of parent element which it get xtype added to..
16816 * @cfg {String} order
16817 * Used to set the order in which elements are created (usefull for multiple tabs)
16822 * @cfg {String} name
16823 * String to display while loading.
16827 * @cfg {String} region
16828 * Region to render component to (defaults to center)
16833 * @cfg {Array} items
16834 * A single item array - the first element is the root of the tree..
16835 * It's done this way to stay compatible with the Xtype system...
16841 * The method that retuns the tree of parts that make up this compoennt
16848 * render element to dom or tree
16849 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16852 render : function(el)
16856 var hp = this.parent ? 1 : 0;
16857 Roo.debug && Roo.log(this);
16859 var tree = this._tree ? this._tree() : this.tree();
16862 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16863 // if parent is a '#.....' string, then let's use that..
16864 var ename = this.parent.substr(1);
16865 this.parent = false;
16866 Roo.debug && Roo.log(ename);
16868 case 'bootstrap-body':
16869 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16870 // this is the BorderLayout standard?
16871 this.parent = { el : true };
16874 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16875 // need to insert stuff...
16877 el : new Roo.bootstrap.layout.Border({
16878 el : document.body,
16884 tabPosition: 'top',
16885 //resizeTabs: true,
16886 alwaysShowTabs: true,
16896 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16897 this.parent = { el : new Roo.bootstrap.Body() };
16898 Roo.debug && Roo.log("setting el to doc body");
16901 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16905 this.parent = { el : true};
16908 el = Roo.get(ename);
16909 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16910 this.parent = { el : true};
16917 if (!el && !this.parent) {
16918 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16923 Roo.debug && Roo.log("EL:");
16924 Roo.debug && Roo.log(el);
16925 Roo.debug && Roo.log("this.parent.el:");
16926 Roo.debug && Roo.log(this.parent.el);
16929 // altertive root elements ??? - we need a better way to indicate these.
16930 var is_alt = Roo.XComponent.is_alt ||
16931 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16932 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16933 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16937 if (!this.parent && is_alt) {
16938 //el = Roo.get(document.body);
16939 this.parent = { el : true };
16944 if (!this.parent) {
16946 Roo.debug && Roo.log("no parent - creating one");
16948 el = el ? Roo.get(el) : false;
16950 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16953 el : new Roo.bootstrap.layout.Border({
16954 el: el || document.body,
16960 tabPosition: 'top',
16961 //resizeTabs: true,
16962 alwaysShowTabs: false,
16965 overflow: 'visible'
16971 // it's a top level one..
16973 el : new Roo.BorderLayout(el || document.body, {
16978 tabPosition: 'top',
16979 //resizeTabs: true,
16980 alwaysShowTabs: el && hp? false : true,
16981 hideTabs: el || !hp ? true : false,
16989 if (!this.parent.el) {
16990 // probably an old style ctor, which has been disabled.
16994 // The 'tree' method is '_tree now'
16996 tree.region = tree.region || this.region;
16997 var is_body = false;
16998 if (this.parent.el === true) {
16999 // bootstrap... - body..
17003 this.parent.el = Roo.factory(tree);
17007 this.el = this.parent.el.addxtype(tree, undefined, is_body);
17008 this.fireEvent('built', this);
17010 this.panel = this.el;
17011 this.layout = this.panel.layout;
17012 this.parentLayout = this.parent.layout || false;
17018 Roo.apply(Roo.XComponent, {
17020 * @property hideProgress
17021 * true to disable the building progress bar.. usefull on single page renders.
17024 hideProgress : false,
17026 * @property buildCompleted
17027 * True when the builder has completed building the interface.
17030 buildCompleted : false,
17033 * @property topModule
17034 * the upper most module - uses document.element as it's constructor.
17041 * @property modules
17042 * array of modules to be created by registration system.
17043 * @type {Array} of Roo.XComponent
17048 * @property elmodules
17049 * array of modules to be created by which use #ID
17050 * @type {Array} of Roo.XComponent
17057 * Is an alternative Root - normally used by bootstrap or other systems,
17058 * where the top element in the tree can wrap 'body'
17059 * @type {boolean} (default false)
17064 * @property build_from_html
17065 * Build elements from html - used by bootstrap HTML stuff
17066 * - this is cleared after build is completed
17067 * @type {boolean} (default false)
17070 build_from_html : false,
17072 * Register components to be built later.
17074 * This solves the following issues
17075 * - Building is not done on page load, but after an authentication process has occured.
17076 * - Interface elements are registered on page load
17077 * - Parent Interface elements may not be loaded before child, so this handles that..
17084 module : 'Pman.Tab.projectMgr',
17086 parent : 'Pman.layout',
17087 disabled : false, // or use a function..
17090 * * @param {Object} details about module
17092 register : function(obj) {
17094 Roo.XComponent.event.fireEvent('register', obj);
17095 switch(typeof(obj.disabled) ) {
17101 if ( obj.disabled() ) {
17107 if (obj.disabled || obj.region == '#disabled') {
17113 this.modules.push(obj);
17117 * convert a string to an object..
17118 * eg. 'AAA.BBB' -> finds AAA.BBB
17122 toObject : function(str)
17124 if (!str || typeof(str) == 'object') {
17127 if (str.substring(0,1) == '#') {
17131 var ar = str.split('.');
17136 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17138 throw "Module not found : " + str;
17142 throw "Module not found : " + str;
17144 Roo.each(ar, function(e) {
17145 if (typeof(o[e]) == 'undefined') {
17146 throw "Module not found : " + str;
17157 * move modules into their correct place in the tree..
17160 preBuild : function ()
17163 Roo.each(this.modules , function (obj)
17165 Roo.XComponent.event.fireEvent('beforebuild', obj);
17167 var opar = obj.parent;
17169 obj.parent = this.toObject(opar);
17171 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17176 Roo.debug && Roo.log("GOT top level module");
17177 Roo.debug && Roo.log(obj);
17178 obj.modules = new Roo.util.MixedCollection(false,
17179 function(o) { return o.order + '' }
17181 this.topModule = obj;
17184 // parent is a string (usually a dom element name..)
17185 if (typeof(obj.parent) == 'string') {
17186 this.elmodules.push(obj);
17189 if (obj.parent.constructor != Roo.XComponent) {
17190 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17192 if (!obj.parent.modules) {
17193 obj.parent.modules = new Roo.util.MixedCollection(false,
17194 function(o) { return o.order + '' }
17197 if (obj.parent.disabled) {
17198 obj.disabled = true;
17200 obj.parent.modules.add(obj);
17205 * make a list of modules to build.
17206 * @return {Array} list of modules.
17209 buildOrder : function()
17212 var cmp = function(a,b) {
17213 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17215 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17216 throw "No top level modules to build";
17219 // make a flat list in order of modules to build.
17220 var mods = this.topModule ? [ this.topModule ] : [];
17223 // elmodules (is a list of DOM based modules )
17224 Roo.each(this.elmodules, function(e) {
17226 if (!this.topModule &&
17227 typeof(e.parent) == 'string' &&
17228 e.parent.substring(0,1) == '#' &&
17229 Roo.get(e.parent.substr(1))
17232 _this.topModule = e;
17238 // add modules to their parents..
17239 var addMod = function(m) {
17240 Roo.debug && Roo.log("build Order: add: " + m.name);
17243 if (m.modules && !m.disabled) {
17244 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17245 m.modules.keySort('ASC', cmp );
17246 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17248 m.modules.each(addMod);
17250 Roo.debug && Roo.log("build Order: no child modules");
17252 // not sure if this is used any more..
17254 m.finalize.name = m.name + " (clean up) ";
17255 mods.push(m.finalize);
17259 if (this.topModule && this.topModule.modules) {
17260 this.topModule.modules.keySort('ASC', cmp );
17261 this.topModule.modules.each(addMod);
17267 * Build the registered modules.
17268 * @param {Object} parent element.
17269 * @param {Function} optional method to call after module has been added.
17273 build : function(opts)
17276 if (typeof(opts) != 'undefined') {
17277 Roo.apply(this,opts);
17281 var mods = this.buildOrder();
17283 //this.allmods = mods;
17284 //Roo.debug && Roo.log(mods);
17286 if (!mods.length) { // should not happen
17287 throw "NO modules!!!";
17291 var msg = "Building Interface...";
17292 // flash it up as modal - so we store the mask!?
17293 if (!this.hideProgress && Roo.MessageBox) {
17294 Roo.MessageBox.show({ title: 'loading' });
17295 Roo.MessageBox.show({
17296 title: "Please wait...",
17306 var total = mods.length;
17309 var progressRun = function() {
17310 if (!mods.length) {
17311 Roo.debug && Roo.log('hide?');
17312 if (!this.hideProgress && Roo.MessageBox) {
17313 Roo.MessageBox.hide();
17315 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17317 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17323 var m = mods.shift();
17326 Roo.debug && Roo.log(m);
17327 // not sure if this is supported any more.. - modules that are are just function
17328 if (typeof(m) == 'function') {
17330 return progressRun.defer(10, _this);
17334 msg = "Building Interface " + (total - mods.length) +
17336 (m.name ? (' - ' + m.name) : '');
17337 Roo.debug && Roo.log(msg);
17338 if (!_this.hideProgress && Roo.MessageBox) {
17339 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17343 // is the module disabled?
17344 var disabled = (typeof(m.disabled) == 'function') ?
17345 m.disabled.call(m.module.disabled) : m.disabled;
17349 return progressRun(); // we do not update the display!
17357 // it's 10 on top level, and 1 on others??? why...
17358 return progressRun.defer(10, _this);
17361 progressRun.defer(1, _this);
17367 * Overlay a set of modified strings onto a component
17368 * This is dependant on our builder exporting the strings and 'named strings' elements.
17370 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17371 * @param {Object} associative array of 'named' string and it's new value.
17374 overlayStrings : function( component, strings )
17376 if (typeof(component['_named_strings']) == 'undefined') {
17377 throw "ERROR: component does not have _named_strings";
17379 for ( var k in strings ) {
17380 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17381 if (md !== false) {
17382 component['_strings'][md] = strings[k];
17384 Roo.log('could not find named string: ' + k + ' in');
17385 Roo.log(component);
17400 * wrapper for event.on - aliased later..
17401 * Typically use to register a event handler for register:
17403 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17412 Roo.XComponent.event = new Roo.util.Observable({
17416 * Fires when an Component is registered,
17417 * set the disable property on the Component to stop registration.
17418 * @param {Roo.XComponent} c the component being registerd.
17423 * @event beforebuild
17424 * Fires before each Component is built
17425 * can be used to apply permissions.
17426 * @param {Roo.XComponent} c the component being registerd.
17429 'beforebuild' : true,
17431 * @event buildcomplete
17432 * Fires on the top level element when all elements have been built
17433 * @param {Roo.XComponent} the top level component.
17435 'buildcomplete' : true
17440 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17443 * marked - a markdown parser
17444 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17445 * https://github.com/chjj/marked
17451 * Roo.Markdown - is a very crude wrapper around marked..
17455 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17457 * Note: move the sample code to the bottom of this
17458 * file before uncommenting it.
17463 Roo.Markdown.toHtml = function(text) {
17465 var c = new Roo.Markdown.marked.setOptions({
17466 renderer: new Roo.Markdown.marked.Renderer(),
17477 text = text.replace(/\\\n/g,' ');
17478 return Roo.Markdown.marked(text);
17483 // Wraps all "globals" so that the only thing
17484 // exposed is makeHtml().
17490 * eval:var:unescape
17498 var escape = function (html, encode) {
17500 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17501 .replace(/</g, '<')
17502 .replace(/>/g, '>')
17503 .replace(/"/g, '"')
17504 .replace(/'/g, ''');
17507 var unescape = function (html) {
17508 // explicitly match decimal, hex, and named HTML entities
17509 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17510 n = n.toLowerCase();
17511 if (n === 'colon') { return ':'; }
17512 if (n.charAt(0) === '#') {
17513 return n.charAt(1) === 'x'
17514 ? String.fromCharCode(parseInt(n.substring(2), 16))
17515 : String.fromCharCode(+n.substring(1));
17521 var replace = function (regex, opt) {
17522 regex = regex.source;
17524 return function self(name, val) {
17525 if (!name) { return new RegExp(regex, opt); }
17526 val = val.source || val;
17527 val = val.replace(/(^|[^\[])\^/g, '$1');
17528 regex = regex.replace(name, val);
17537 var noop = function () {}
17543 var merge = function (obj) {
17548 for (; i < arguments.length; i++) {
17549 target = arguments[i];
17550 for (key in target) {
17551 if (Object.prototype.hasOwnProperty.call(target, key)) {
17552 obj[key] = target[key];
17562 * Block-Level Grammar
17570 code: /^( {4}[^\n]+\n*)+/,
17572 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17573 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17575 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17576 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17577 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17578 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17579 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17581 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17585 block.bullet = /(?:[*+-]|\d+\.)/;
17586 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17587 block.item = replace(block.item, 'gm')
17588 (/bull/g, block.bullet)
17591 block.list = replace(block.list)
17592 (/bull/g, block.bullet)
17593 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17594 ('def', '\\n+(?=' + block.def.source + ')')
17597 block.blockquote = replace(block.blockquote)
17601 block._tag = '(?!(?:'
17602 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17603 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17604 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17606 block.html = replace(block.html)
17607 ('comment', /<!--[\s\S]*?-->/)
17608 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17609 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17610 (/tag/g, block._tag)
17613 block.paragraph = replace(block.paragraph)
17615 ('heading', block.heading)
17616 ('lheading', block.lheading)
17617 ('blockquote', block.blockquote)
17618 ('tag', '<' + block._tag)
17623 * Normal Block Grammar
17626 block.normal = merge({}, block);
17629 * GFM Block Grammar
17632 block.gfm = merge({}, block.normal, {
17633 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17635 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17638 block.gfm.paragraph = replace(block.paragraph)
17640 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17641 + block.list.source.replace('\\1', '\\3') + '|')
17645 * GFM + Tables Block Grammar
17648 block.tables = merge({}, block.gfm, {
17649 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17650 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17657 var Lexer = function (options) {
17659 this.tokens.links = {};
17660 this.options = options || marked.defaults;
17661 this.rules = block.normal;
17663 if (this.options.gfm) {
17664 if (this.options.tables) {
17665 this.rules = block.tables;
17667 this.rules = block.gfm;
17673 * Expose Block Rules
17676 Lexer.rules = block;
17679 * Static Lex Method
17682 Lexer.lex = function(src, options) {
17683 var lexer = new Lexer(options);
17684 return lexer.lex(src);
17691 Lexer.prototype.lex = function(src) {
17693 .replace(/\r\n|\r/g, '\n')
17694 .replace(/\t/g, ' ')
17695 .replace(/\u00a0/g, ' ')
17696 .replace(/\u2424/g, '\n');
17698 return this.token(src, true);
17705 Lexer.prototype.token = function(src, top, bq) {
17706 var src = src.replace(/^ +$/gm, '')
17719 if (cap = this.rules.newline.exec(src)) {
17720 src = src.substring(cap[0].length);
17721 if (cap[0].length > 1) {
17729 if (cap = this.rules.code.exec(src)) {
17730 src = src.substring(cap[0].length);
17731 cap = cap[0].replace(/^ {4}/gm, '');
17734 text: !this.options.pedantic
17735 ? cap.replace(/\n+$/, '')
17742 if (cap = this.rules.fences.exec(src)) {
17743 src = src.substring(cap[0].length);
17753 if (cap = this.rules.heading.exec(src)) {
17754 src = src.substring(cap[0].length);
17757 depth: cap[1].length,
17763 // table no leading pipe (gfm)
17764 if (top && (cap = this.rules.nptable.exec(src))) {
17765 src = src.substring(cap[0].length);
17769 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17770 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17771 cells: cap[3].replace(/\n$/, '').split('\n')
17774 for (i = 0; i < item.align.length; i++) {
17775 if (/^ *-+: *$/.test(item.align[i])) {
17776 item.align[i] = 'right';
17777 } else if (/^ *:-+: *$/.test(item.align[i])) {
17778 item.align[i] = 'center';
17779 } else if (/^ *:-+ *$/.test(item.align[i])) {
17780 item.align[i] = 'left';
17782 item.align[i] = null;
17786 for (i = 0; i < item.cells.length; i++) {
17787 item.cells[i] = item.cells[i].split(/ *\| */);
17790 this.tokens.push(item);
17796 if (cap = this.rules.lheading.exec(src)) {
17797 src = src.substring(cap[0].length);
17800 depth: cap[2] === '=' ? 1 : 2,
17807 if (cap = this.rules.hr.exec(src)) {
17808 src = src.substring(cap[0].length);
17816 if (cap = this.rules.blockquote.exec(src)) {
17817 src = src.substring(cap[0].length);
17820 type: 'blockquote_start'
17823 cap = cap[0].replace(/^ *> ?/gm, '');
17825 // Pass `top` to keep the current
17826 // "toplevel" state. This is exactly
17827 // how markdown.pl works.
17828 this.token(cap, top, true);
17831 type: 'blockquote_end'
17838 if (cap = this.rules.list.exec(src)) {
17839 src = src.substring(cap[0].length);
17843 type: 'list_start',
17844 ordered: bull.length > 1
17847 // Get each top-level item.
17848 cap = cap[0].match(this.rules.item);
17854 for (; i < l; i++) {
17857 // Remove the list item's bullet
17858 // so it is seen as the next token.
17859 space = item.length;
17860 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17862 // Outdent whatever the
17863 // list item contains. Hacky.
17864 if (~item.indexOf('\n ')) {
17865 space -= item.length;
17866 item = !this.options.pedantic
17867 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17868 : item.replace(/^ {1,4}/gm, '');
17871 // Determine whether the next list item belongs here.
17872 // Backpedal if it does not belong in this list.
17873 if (this.options.smartLists && i !== l - 1) {
17874 b = block.bullet.exec(cap[i + 1])[0];
17875 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17876 src = cap.slice(i + 1).join('\n') + src;
17881 // Determine whether item is loose or not.
17882 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17883 // for discount behavior.
17884 loose = next || /\n\n(?!\s*$)/.test(item);
17886 next = item.charAt(item.length - 1) === '\n';
17887 if (!loose) { loose = next; }
17892 ? 'loose_item_start'
17893 : 'list_item_start'
17897 this.token(item, false, bq);
17900 type: 'list_item_end'
17912 if (cap = this.rules.html.exec(src)) {
17913 src = src.substring(cap[0].length);
17915 type: this.options.sanitize
17918 pre: !this.options.sanitizer
17919 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17926 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17927 src = src.substring(cap[0].length);
17928 this.tokens.links[cap[1].toLowerCase()] = {
17936 if (top && (cap = this.rules.table.exec(src))) {
17937 src = src.substring(cap[0].length);
17941 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17942 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17943 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17946 for (i = 0; i < item.align.length; i++) {
17947 if (/^ *-+: *$/.test(item.align[i])) {
17948 item.align[i] = 'right';
17949 } else if (/^ *:-+: *$/.test(item.align[i])) {
17950 item.align[i] = 'center';
17951 } else if (/^ *:-+ *$/.test(item.align[i])) {
17952 item.align[i] = 'left';
17954 item.align[i] = null;
17958 for (i = 0; i < item.cells.length; i++) {
17959 item.cells[i] = item.cells[i]
17960 .replace(/^ *\| *| *\| *$/g, '')
17964 this.tokens.push(item);
17969 // top-level paragraph
17970 if (top && (cap = this.rules.paragraph.exec(src))) {
17971 src = src.substring(cap[0].length);
17974 text: cap[1].charAt(cap[1].length - 1) === '\n'
17975 ? cap[1].slice(0, -1)
17982 if (cap = this.rules.text.exec(src)) {
17983 // Top-level should never reach here.
17984 src = src.substring(cap[0].length);
17994 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17998 return this.tokens;
18002 * Inline-Level Grammar
18006 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18007 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18009 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18010 link: /^!?\[(inside)\]\(href\)/,
18011 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18012 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18013 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18014 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18015 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18016 br: /^ {2,}\n(?!\s*$)/,
18018 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18021 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18022 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18024 inline.link = replace(inline.link)
18025 ('inside', inline._inside)
18026 ('href', inline._href)
18029 inline.reflink = replace(inline.reflink)
18030 ('inside', inline._inside)
18034 * Normal Inline Grammar
18037 inline.normal = merge({}, inline);
18040 * Pedantic Inline Grammar
18043 inline.pedantic = merge({}, inline.normal, {
18044 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18045 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18049 * GFM Inline Grammar
18052 inline.gfm = merge({}, inline.normal, {
18053 escape: replace(inline.escape)('])', '~|])')(),
18054 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18055 del: /^~~(?=\S)([\s\S]*?\S)~~/,
18056 text: replace(inline.text)
18058 ('|', '|https?://|')
18063 * GFM + Line Breaks Inline Grammar
18066 inline.breaks = merge({}, inline.gfm, {
18067 br: replace(inline.br)('{2,}', '*')(),
18068 text: replace(inline.gfm.text)('{2,}', '*')()
18072 * Inline Lexer & Compiler
18075 var InlineLexer = function (links, options) {
18076 this.options = options || marked.defaults;
18077 this.links = links;
18078 this.rules = inline.normal;
18079 this.renderer = this.options.renderer || new Renderer;
18080 this.renderer.options = this.options;
18084 Error('Tokens array requires a `links` property.');
18087 if (this.options.gfm) {
18088 if (this.options.breaks) {
18089 this.rules = inline.breaks;
18091 this.rules = inline.gfm;
18093 } else if (this.options.pedantic) {
18094 this.rules = inline.pedantic;
18099 * Expose Inline Rules
18102 InlineLexer.rules = inline;
18105 * Static Lexing/Compiling Method
18108 InlineLexer.output = function(src, links, options) {
18109 var inline = new InlineLexer(links, options);
18110 return inline.output(src);
18117 InlineLexer.prototype.output = function(src) {
18126 if (cap = this.rules.escape.exec(src)) {
18127 src = src.substring(cap[0].length);
18133 if (cap = this.rules.autolink.exec(src)) {
18134 src = src.substring(cap[0].length);
18135 if (cap[2] === '@') {
18136 text = cap[1].charAt(6) === ':'
18137 ? this.mangle(cap[1].substring(7))
18138 : this.mangle(cap[1]);
18139 href = this.mangle('mailto:') + text;
18141 text = escape(cap[1]);
18144 out += this.renderer.link(href, null, text);
18149 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18150 src = src.substring(cap[0].length);
18151 text = escape(cap[1]);
18153 out += this.renderer.link(href, null, text);
18158 if (cap = this.rules.tag.exec(src)) {
18159 if (!this.inLink && /^<a /i.test(cap[0])) {
18160 this.inLink = true;
18161 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18162 this.inLink = false;
18164 src = src.substring(cap[0].length);
18165 out += this.options.sanitize
18166 ? this.options.sanitizer
18167 ? this.options.sanitizer(cap[0])
18174 if (cap = this.rules.link.exec(src)) {
18175 src = src.substring(cap[0].length);
18176 this.inLink = true;
18177 out += this.outputLink(cap, {
18181 this.inLink = false;
18186 if ((cap = this.rules.reflink.exec(src))
18187 || (cap = this.rules.nolink.exec(src))) {
18188 src = src.substring(cap[0].length);
18189 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18190 link = this.links[link.toLowerCase()];
18191 if (!link || !link.href) {
18192 out += cap[0].charAt(0);
18193 src = cap[0].substring(1) + src;
18196 this.inLink = true;
18197 out += this.outputLink(cap, link);
18198 this.inLink = false;
18203 if (cap = this.rules.strong.exec(src)) {
18204 src = src.substring(cap[0].length);
18205 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18210 if (cap = this.rules.em.exec(src)) {
18211 src = src.substring(cap[0].length);
18212 out += this.renderer.em(this.output(cap[2] || cap[1]));
18217 if (cap = this.rules.code.exec(src)) {
18218 src = src.substring(cap[0].length);
18219 out += this.renderer.codespan(escape(cap[2], true));
18224 if (cap = this.rules.br.exec(src)) {
18225 src = src.substring(cap[0].length);
18226 out += this.renderer.br();
18231 if (cap = this.rules.del.exec(src)) {
18232 src = src.substring(cap[0].length);
18233 out += this.renderer.del(this.output(cap[1]));
18238 if (cap = this.rules.text.exec(src)) {
18239 src = src.substring(cap[0].length);
18240 out += this.renderer.text(escape(this.smartypants(cap[0])));
18246 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18257 InlineLexer.prototype.outputLink = function(cap, link) {
18258 var href = escape(link.href)
18259 , title = link.title ? escape(link.title) : null;
18261 return cap[0].charAt(0) !== '!'
18262 ? this.renderer.link(href, title, this.output(cap[1]))
18263 : this.renderer.image(href, title, escape(cap[1]));
18267 * Smartypants Transformations
18270 InlineLexer.prototype.smartypants = function(text) {
18271 if (!this.options.smartypants) { return text; }
18274 .replace(/---/g, '\u2014')
18276 .replace(/--/g, '\u2013')
18278 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18279 // closing singles & apostrophes
18280 .replace(/'/g, '\u2019')
18282 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18284 .replace(/"/g, '\u201d')
18286 .replace(/\.{3}/g, '\u2026');
18293 InlineLexer.prototype.mangle = function(text) {
18294 if (!this.options.mangle) { return text; }
18300 for (; i < l; i++) {
18301 ch = text.charCodeAt(i);
18302 if (Math.random() > 0.5) {
18303 ch = 'x' + ch.toString(16);
18305 out += '&#' + ch + ';';
18316 * eval:var:Renderer
18319 var Renderer = function (options) {
18320 this.options = options || {};
18323 Renderer.prototype.code = function(code, lang, escaped) {
18324 if (this.options.highlight) {
18325 var out = this.options.highlight(code, lang);
18326 if (out != null && out !== code) {
18331 // hack!!! - it's already escapeD?
18336 return '<pre><code>'
18337 + (escaped ? code : escape(code, true))
18338 + '\n</code></pre>';
18341 return '<pre><code class="'
18342 + this.options.langPrefix
18343 + escape(lang, true)
18345 + (escaped ? code : escape(code, true))
18346 + '\n</code></pre>\n';
18349 Renderer.prototype.blockquote = function(quote) {
18350 return '<blockquote>\n' + quote + '</blockquote>\n';
18353 Renderer.prototype.html = function(html) {
18357 Renderer.prototype.heading = function(text, level, raw) {
18361 + this.options.headerPrefix
18362 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18370 Renderer.prototype.hr = function() {
18371 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18374 Renderer.prototype.list = function(body, ordered) {
18375 var type = ordered ? 'ol' : 'ul';
18376 return '<' + type + '>\n' + body + '</' + type + '>\n';
18379 Renderer.prototype.listitem = function(text) {
18380 return '<li>' + text + '</li>\n';
18383 Renderer.prototype.paragraph = function(text) {
18384 return '<p>' + text + '</p>\n';
18387 Renderer.prototype.table = function(header, body) {
18388 return '<table class="table table-striped">\n'
18398 Renderer.prototype.tablerow = function(content) {
18399 return '<tr>\n' + content + '</tr>\n';
18402 Renderer.prototype.tablecell = function(content, flags) {
18403 var type = flags.header ? 'th' : 'td';
18404 var tag = flags.align
18405 ? '<' + type + ' style="text-align:' + flags.align + '">'
18406 : '<' + type + '>';
18407 return tag + content + '</' + type + '>\n';
18410 // span level renderer
18411 Renderer.prototype.strong = function(text) {
18412 return '<strong>' + text + '</strong>';
18415 Renderer.prototype.em = function(text) {
18416 return '<em>' + text + '</em>';
18419 Renderer.prototype.codespan = function(text) {
18420 return '<code>' + text + '</code>';
18423 Renderer.prototype.br = function() {
18424 return this.options.xhtml ? '<br/>' : '<br>';
18427 Renderer.prototype.del = function(text) {
18428 return '<del>' + text + '</del>';
18431 Renderer.prototype.link = function(href, title, text) {
18432 if (this.options.sanitize) {
18434 var prot = decodeURIComponent(unescape(href))
18435 .replace(/[^\w:]/g, '')
18440 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18444 var out = '<a href="' + href + '"';
18446 out += ' title="' + title + '"';
18448 out += '>' + text + '</a>';
18452 Renderer.prototype.image = function(href, title, text) {
18453 var out = '<img src="' + href + '" alt="' + text + '"';
18455 out += ' title="' + title + '"';
18457 out += this.options.xhtml ? '/>' : '>';
18461 Renderer.prototype.text = function(text) {
18466 * Parsing & Compiling
18472 var Parser= function (options) {
18475 this.options = options || marked.defaults;
18476 this.options.renderer = this.options.renderer || new Renderer;
18477 this.renderer = this.options.renderer;
18478 this.renderer.options = this.options;
18482 * Static Parse Method
18485 Parser.parse = function(src, options, renderer) {
18486 var parser = new Parser(options, renderer);
18487 return parser.parse(src);
18494 Parser.prototype.parse = function(src) {
18495 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18496 this.tokens = src.reverse();
18499 while (this.next()) {
18510 Parser.prototype.next = function() {
18511 return this.token = this.tokens.pop();
18515 * Preview Next Token
18518 Parser.prototype.peek = function() {
18519 return this.tokens[this.tokens.length - 1] || 0;
18523 * Parse Text Tokens
18526 Parser.prototype.parseText = function() {
18527 var body = this.token.text;
18529 while (this.peek().type === 'text') {
18530 body += '\n' + this.next().text;
18533 return this.inline.output(body);
18537 * Parse Current Token
18540 Parser.prototype.tok = function() {
18541 switch (this.token.type) {
18546 return this.renderer.hr();
18549 return this.renderer.heading(
18550 this.inline.output(this.token.text),
18555 return this.renderer.code(this.token.text,
18557 this.token.escaped);
18570 for (i = 0; i < this.token.header.length; i++) {
18571 flags = { header: true, align: this.token.align[i] };
18572 cell += this.renderer.tablecell(
18573 this.inline.output(this.token.header[i]),
18574 { header: true, align: this.token.align[i] }
18577 header += this.renderer.tablerow(cell);
18579 for (i = 0; i < this.token.cells.length; i++) {
18580 row = this.token.cells[i];
18583 for (j = 0; j < row.length; j++) {
18584 cell += this.renderer.tablecell(
18585 this.inline.output(row[j]),
18586 { header: false, align: this.token.align[j] }
18590 body += this.renderer.tablerow(cell);
18592 return this.renderer.table(header, body);
18594 case 'blockquote_start': {
18597 while (this.next().type !== 'blockquote_end') {
18598 body += this.tok();
18601 return this.renderer.blockquote(body);
18603 case 'list_start': {
18605 , ordered = this.token.ordered;
18607 while (this.next().type !== 'list_end') {
18608 body += this.tok();
18611 return this.renderer.list(body, ordered);
18613 case 'list_item_start': {
18616 while (this.next().type !== 'list_item_end') {
18617 body += this.token.type === 'text'
18622 return this.renderer.listitem(body);
18624 case 'loose_item_start': {
18627 while (this.next().type !== 'list_item_end') {
18628 body += this.tok();
18631 return this.renderer.listitem(body);
18634 var html = !this.token.pre && !this.options.pedantic
18635 ? this.inline.output(this.token.text)
18637 return this.renderer.html(html);
18639 case 'paragraph': {
18640 return this.renderer.paragraph(this.inline.output(this.token.text));
18643 return this.renderer.paragraph(this.parseText());
18655 var marked = function (src, opt, callback) {
18656 if (callback || typeof opt === 'function') {
18662 opt = merge({}, marked.defaults, opt || {});
18664 var highlight = opt.highlight
18670 tokens = Lexer.lex(src, opt)
18672 return callback(e);
18675 pending = tokens.length;
18679 var done = function(err) {
18681 opt.highlight = highlight;
18682 return callback(err);
18688 out = Parser.parse(tokens, opt);
18693 opt.highlight = highlight;
18697 : callback(null, out);
18700 if (!highlight || highlight.length < 3) {
18704 delete opt.highlight;
18706 if (!pending) { return done(); }
18708 for (; i < tokens.length; i++) {
18710 if (token.type !== 'code') {
18711 return --pending || done();
18713 return highlight(token.text, token.lang, function(err, code) {
18714 if (err) { return done(err); }
18715 if (code == null || code === token.text) {
18716 return --pending || done();
18719 token.escaped = true;
18720 --pending || done();
18728 if (opt) { opt = merge({}, marked.defaults, opt); }
18729 return Parser.parse(Lexer.lex(src, opt), opt);
18731 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18732 if ((opt || marked.defaults).silent) {
18733 return '<p>An error occured:</p><pre>'
18734 + escape(e.message + '', true)
18746 marked.setOptions = function(opt) {
18747 merge(marked.defaults, opt);
18751 marked.defaults = {
18762 langPrefix: 'lang-',
18763 smartypants: false,
18765 renderer: new Renderer,
18773 marked.Parser = Parser;
18774 marked.parser = Parser.parse;
18776 marked.Renderer = Renderer;
18778 marked.Lexer = Lexer;
18779 marked.lexer = Lexer.lex;
18781 marked.InlineLexer = InlineLexer;
18782 marked.inlineLexer = InlineLexer.output;
18784 marked.parse = marked;
18786 Roo.Markdown.marked = marked;
18790 * Ext JS Library 1.1.1
18791 * Copyright(c) 2006-2007, Ext JS, LLC.
18793 * Originally Released Under LGPL - original licence link has changed is not relivant.
18796 * <script type="text/javascript">
18802 * These classes are derivatives of the similarly named classes in the YUI Library.
18803 * The original license:
18804 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18805 * Code licensed under the BSD License:
18806 * http://developer.yahoo.net/yui/license.txt
18811 var Event=Roo.EventManager;
18812 var Dom=Roo.lib.Dom;
18815 * @class Roo.dd.DragDrop
18816 * @extends Roo.util.Observable
18817 * Defines the interface and base operation of items that that can be
18818 * dragged or can be drop targets. It was designed to be extended, overriding
18819 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18820 * Up to three html elements can be associated with a DragDrop instance:
18822 * <li>linked element: the element that is passed into the constructor.
18823 * This is the element which defines the boundaries for interaction with
18824 * other DragDrop objects.</li>
18825 * <li>handle element(s): The drag operation only occurs if the element that
18826 * was clicked matches a handle element. By default this is the linked
18827 * element, but there are times that you will want only a portion of the
18828 * linked element to initiate the drag operation, and the setHandleElId()
18829 * method provides a way to define this.</li>
18830 * <li>drag element: this represents the element that would be moved along
18831 * with the cursor during a drag operation. By default, this is the linked
18832 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18833 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18836 * This class should not be instantiated until the onload event to ensure that
18837 * the associated elements are available.
18838 * The following would define a DragDrop obj that would interact with any
18839 * other DragDrop obj in the "group1" group:
18841 * dd = new Roo.dd.DragDrop("div1", "group1");
18843 * Since none of the event handlers have been implemented, nothing would
18844 * actually happen if you were to run the code above. Normally you would
18845 * override this class or one of the default implementations, but you can
18846 * also override the methods you want on an instance of the class...
18848 * dd.onDragDrop = function(e, id) {
18849 * alert("dd was dropped on " + id);
18853 * @param {String} id of the element that is linked to this instance
18854 * @param {String} sGroup the group of related DragDrop objects
18855 * @param {object} config an object containing configurable attributes
18856 * Valid properties for DragDrop:
18857 * padding, isTarget, maintainOffset, primaryButtonOnly
18859 Roo.dd.DragDrop = function(id, sGroup, config) {
18861 this.init(id, sGroup, config);
18866 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18869 * The id of the element associated with this object. This is what we
18870 * refer to as the "linked element" because the size and position of
18871 * this element is used to determine when the drag and drop objects have
18879 * Configuration attributes passed into the constructor
18886 * The id of the element that will be dragged. By default this is same
18887 * as the linked element , but could be changed to another element. Ex:
18889 * @property dragElId
18896 * the id of the element that initiates the drag operation. By default
18897 * this is the linked element, but could be changed to be a child of this
18898 * element. This lets us do things like only starting the drag when the
18899 * header element within the linked html element is clicked.
18900 * @property handleElId
18907 * An associative array of HTML tags that will be ignored if clicked.
18908 * @property invalidHandleTypes
18909 * @type {string: string}
18911 invalidHandleTypes: null,
18914 * An associative array of ids for elements that will be ignored if clicked
18915 * @property invalidHandleIds
18916 * @type {string: string}
18918 invalidHandleIds: null,
18921 * An indexted array of css class names for elements that will be ignored
18923 * @property invalidHandleClasses
18926 invalidHandleClasses: null,
18929 * The linked element's absolute X position at the time the drag was
18931 * @property startPageX
18938 * The linked element's absolute X position at the time the drag was
18940 * @property startPageY
18947 * The group defines a logical collection of DragDrop objects that are
18948 * related. Instances only get events when interacting with other
18949 * DragDrop object in the same group. This lets us define multiple
18950 * groups using a single DragDrop subclass if we want.
18952 * @type {string: string}
18957 * Individual drag/drop instances can be locked. This will prevent
18958 * onmousedown start drag.
18966 * Lock this instance
18969 lock: function() { this.locked = true; },
18972 * Unlock this instace
18975 unlock: function() { this.locked = false; },
18978 * By default, all insances can be a drop target. This can be disabled by
18979 * setting isTarget to false.
18986 * The padding configured for this drag and drop object for calculating
18987 * the drop zone intersection with this object.
18994 * Cached reference to the linked element
18995 * @property _domRef
19001 * Internal typeof flag
19002 * @property __ygDragDrop
19005 __ygDragDrop: true,
19008 * Set to true when horizontal contraints are applied
19009 * @property constrainX
19016 * Set to true when vertical contraints are applied
19017 * @property constrainY
19024 * The left constraint
19032 * The right constraint
19040 * The up constraint
19049 * The down constraint
19057 * Maintain offsets when we resetconstraints. Set to true when you want
19058 * the position of the element relative to its parent to stay the same
19059 * when the page changes
19061 * @property maintainOffset
19064 maintainOffset: false,
19067 * Array of pixel locations the element will snap to if we specified a
19068 * horizontal graduation/interval. This array is generated automatically
19069 * when you define a tick interval.
19076 * Array of pixel locations the element will snap to if we specified a
19077 * vertical graduation/interval. This array is generated automatically
19078 * when you define a tick interval.
19085 * By default the drag and drop instance will only respond to the primary
19086 * button click (left button for a right-handed mouse). Set to true to
19087 * allow drag and drop to start with any mouse click that is propogated
19089 * @property primaryButtonOnly
19092 primaryButtonOnly: true,
19095 * The availabe property is false until the linked dom element is accessible.
19096 * @property available
19102 * By default, drags can only be initiated if the mousedown occurs in the
19103 * region the linked element is. This is done in part to work around a
19104 * bug in some browsers that mis-report the mousedown if the previous
19105 * mouseup happened outside of the window. This property is set to true
19106 * if outer handles are defined.
19108 * @property hasOuterHandles
19112 hasOuterHandles: false,
19115 * Code that executes immediately before the startDrag event
19116 * @method b4StartDrag
19119 b4StartDrag: function(x, y) { },
19122 * Abstract method called after a drag/drop object is clicked
19123 * and the drag or mousedown time thresholds have beeen met.
19124 * @method startDrag
19125 * @param {int} X click location
19126 * @param {int} Y click location
19128 startDrag: function(x, y) { /* override this */ },
19131 * Code that executes immediately before the onDrag event
19135 b4Drag: function(e) { },
19138 * Abstract method called during the onMouseMove event while dragging an
19141 * @param {Event} e the mousemove event
19143 onDrag: function(e) { /* override this */ },
19146 * Abstract method called when this element fist begins hovering over
19147 * another DragDrop obj
19148 * @method onDragEnter
19149 * @param {Event} e the mousemove event
19150 * @param {String|DragDrop[]} id In POINT mode, the element
19151 * id this is hovering over. In INTERSECT mode, an array of one or more
19152 * dragdrop items being hovered over.
19154 onDragEnter: function(e, id) { /* override this */ },
19157 * Code that executes immediately before the onDragOver event
19158 * @method b4DragOver
19161 b4DragOver: function(e) { },
19164 * Abstract method called when this element is hovering over another
19166 * @method onDragOver
19167 * @param {Event} e the mousemove event
19168 * @param {String|DragDrop[]} id In POINT mode, the element
19169 * id this is hovering over. In INTERSECT mode, an array of dd items
19170 * being hovered over.
19172 onDragOver: function(e, id) { /* override this */ },
19175 * Code that executes immediately before the onDragOut event
19176 * @method b4DragOut
19179 b4DragOut: function(e) { },
19182 * Abstract method called when we are no longer hovering over an element
19183 * @method onDragOut
19184 * @param {Event} e the mousemove event
19185 * @param {String|DragDrop[]} id In POINT mode, the element
19186 * id this was hovering over. In INTERSECT mode, an array of dd items
19187 * that the mouse is no longer over.
19189 onDragOut: function(e, id) { /* override this */ },
19192 * Code that executes immediately before the onDragDrop event
19193 * @method b4DragDrop
19196 b4DragDrop: function(e) { },
19199 * Abstract method called when this item is dropped on another DragDrop
19201 * @method onDragDrop
19202 * @param {Event} e the mouseup event
19203 * @param {String|DragDrop[]} id In POINT mode, the element
19204 * id this was dropped on. In INTERSECT mode, an array of dd items this
19207 onDragDrop: function(e, id) { /* override this */ },
19210 * Abstract method called when this item is dropped on an area with no
19212 * @method onInvalidDrop
19213 * @param {Event} e the mouseup event
19215 onInvalidDrop: function(e) { /* override this */ },
19218 * Code that executes immediately before the endDrag event
19219 * @method b4EndDrag
19222 b4EndDrag: function(e) { },
19225 * Fired when we are done dragging the object
19227 * @param {Event} e the mouseup event
19229 endDrag: function(e) { /* override this */ },
19232 * Code executed immediately before the onMouseDown event
19233 * @method b4MouseDown
19234 * @param {Event} e the mousedown event
19237 b4MouseDown: function(e) { },
19240 * Event handler that fires when a drag/drop obj gets a mousedown
19241 * @method onMouseDown
19242 * @param {Event} e the mousedown event
19244 onMouseDown: function(e) { /* override this */ },
19247 * Event handler that fires when a drag/drop obj gets a mouseup
19248 * @method onMouseUp
19249 * @param {Event} e the mouseup event
19251 onMouseUp: function(e) { /* override this */ },
19254 * Override the onAvailable method to do what is needed after the initial
19255 * position was determined.
19256 * @method onAvailable
19258 onAvailable: function () {
19262 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19265 defaultPadding : {left:0, right:0, top:0, bottom:0},
19268 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19272 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19273 { dragElId: "existingProxyDiv" });
19274 dd.startDrag = function(){
19275 this.constrainTo("parent-id");
19278 * Or you can initalize it using the {@link Roo.Element} object:
19280 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19281 startDrag : function(){
19282 this.constrainTo("parent-id");
19286 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19287 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19288 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19289 * an object containing the sides to pad. For example: {right:10, bottom:10}
19290 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19292 constrainTo : function(constrainTo, pad, inContent){
19293 if(typeof pad == "number"){
19294 pad = {left: pad, right:pad, top:pad, bottom:pad};
19296 pad = pad || this.defaultPadding;
19297 var b = Roo.get(this.getEl()).getBox();
19298 var ce = Roo.get(constrainTo);
19299 var s = ce.getScroll();
19300 var c, cd = ce.dom;
19301 if(cd == document.body){
19302 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19305 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19309 var topSpace = b.y - c.y;
19310 var leftSpace = b.x - c.x;
19312 this.resetConstraints();
19313 this.setXConstraint(leftSpace - (pad.left||0), // left
19314 c.width - leftSpace - b.width - (pad.right||0) //right
19316 this.setYConstraint(topSpace - (pad.top||0), //top
19317 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19322 * Returns a reference to the linked element
19324 * @return {HTMLElement} the html element
19326 getEl: function() {
19327 if (!this._domRef) {
19328 this._domRef = Roo.getDom(this.id);
19331 return this._domRef;
19335 * Returns a reference to the actual element to drag. By default this is
19336 * the same as the html element, but it can be assigned to another
19337 * element. An example of this can be found in Roo.dd.DDProxy
19338 * @method getDragEl
19339 * @return {HTMLElement} the html element
19341 getDragEl: function() {
19342 return Roo.getDom(this.dragElId);
19346 * Sets up the DragDrop object. Must be called in the constructor of any
19347 * Roo.dd.DragDrop subclass
19349 * @param id the id of the linked element
19350 * @param {String} sGroup the group of related items
19351 * @param {object} config configuration attributes
19353 init: function(id, sGroup, config) {
19354 this.initTarget(id, sGroup, config);
19355 if (!Roo.isTouch) {
19356 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19358 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19359 // Event.on(this.id, "selectstart", Event.preventDefault);
19363 * Initializes Targeting functionality only... the object does not
19364 * get a mousedown handler.
19365 * @method initTarget
19366 * @param id the id of the linked element
19367 * @param {String} sGroup the group of related items
19368 * @param {object} config configuration attributes
19370 initTarget: function(id, sGroup, config) {
19372 // configuration attributes
19373 this.config = config || {};
19375 // create a local reference to the drag and drop manager
19376 this.DDM = Roo.dd.DDM;
19377 // initialize the groups array
19380 // assume that we have an element reference instead of an id if the
19381 // parameter is not a string
19382 if (typeof id !== "string") {
19389 // add to an interaction group
19390 this.addToGroup((sGroup) ? sGroup : "default");
19392 // We don't want to register this as the handle with the manager
19393 // so we just set the id rather than calling the setter.
19394 this.handleElId = id;
19396 // the linked element is the element that gets dragged by default
19397 this.setDragElId(id);
19399 // by default, clicked anchors will not start drag operations.
19400 this.invalidHandleTypes = { A: "A" };
19401 this.invalidHandleIds = {};
19402 this.invalidHandleClasses = [];
19404 this.applyConfig();
19406 this.handleOnAvailable();
19410 * Applies the configuration parameters that were passed into the constructor.
19411 * This is supposed to happen at each level through the inheritance chain. So
19412 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19413 * DragDrop in order to get all of the parameters that are available in
19415 * @method applyConfig
19417 applyConfig: function() {
19419 // configurable properties:
19420 // padding, isTarget, maintainOffset, primaryButtonOnly
19421 this.padding = this.config.padding || [0, 0, 0, 0];
19422 this.isTarget = (this.config.isTarget !== false);
19423 this.maintainOffset = (this.config.maintainOffset);
19424 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19429 * Executed when the linked element is available
19430 * @method handleOnAvailable
19433 handleOnAvailable: function() {
19434 this.available = true;
19435 this.resetConstraints();
19436 this.onAvailable();
19440 * Configures the padding for the target zone in px. Effectively expands
19441 * (or reduces) the virtual object size for targeting calculations.
19442 * Supports css-style shorthand; if only one parameter is passed, all sides
19443 * will have that padding, and if only two are passed, the top and bottom
19444 * will have the first param, the left and right the second.
19445 * @method setPadding
19446 * @param {int} iTop Top pad
19447 * @param {int} iRight Right pad
19448 * @param {int} iBot Bot pad
19449 * @param {int} iLeft Left pad
19451 setPadding: function(iTop, iRight, iBot, iLeft) {
19452 // this.padding = [iLeft, iRight, iTop, iBot];
19453 if (!iRight && 0 !== iRight) {
19454 this.padding = [iTop, iTop, iTop, iTop];
19455 } else if (!iBot && 0 !== iBot) {
19456 this.padding = [iTop, iRight, iTop, iRight];
19458 this.padding = [iTop, iRight, iBot, iLeft];
19463 * Stores the initial placement of the linked element.
19464 * @method setInitialPosition
19465 * @param {int} diffX the X offset, default 0
19466 * @param {int} diffY the Y offset, default 0
19468 setInitPosition: function(diffX, diffY) {
19469 var el = this.getEl();
19471 if (!this.DDM.verifyEl(el)) {
19475 var dx = diffX || 0;
19476 var dy = diffY || 0;
19478 var p = Dom.getXY( el );
19480 this.initPageX = p[0] - dx;
19481 this.initPageY = p[1] - dy;
19483 this.lastPageX = p[0];
19484 this.lastPageY = p[1];
19487 this.setStartPosition(p);
19491 * Sets the start position of the element. This is set when the obj
19492 * is initialized, the reset when a drag is started.
19493 * @method setStartPosition
19494 * @param pos current position (from previous lookup)
19497 setStartPosition: function(pos) {
19498 var p = pos || Dom.getXY( this.getEl() );
19499 this.deltaSetXY = null;
19501 this.startPageX = p[0];
19502 this.startPageY = p[1];
19506 * Add this instance to a group of related drag/drop objects. All
19507 * instances belong to at least one group, and can belong to as many
19508 * groups as needed.
19509 * @method addToGroup
19510 * @param sGroup {string} the name of the group
19512 addToGroup: function(sGroup) {
19513 this.groups[sGroup] = true;
19514 this.DDM.regDragDrop(this, sGroup);
19518 * Remove's this instance from the supplied interaction group
19519 * @method removeFromGroup
19520 * @param {string} sGroup The group to drop
19522 removeFromGroup: function(sGroup) {
19523 if (this.groups[sGroup]) {
19524 delete this.groups[sGroup];
19527 this.DDM.removeDDFromGroup(this, sGroup);
19531 * Allows you to specify that an element other than the linked element
19532 * will be moved with the cursor during a drag
19533 * @method setDragElId
19534 * @param id {string} the id of the element that will be used to initiate the drag
19536 setDragElId: function(id) {
19537 this.dragElId = id;
19541 * Allows you to specify a child of the linked element that should be
19542 * used to initiate the drag operation. An example of this would be if
19543 * you have a content div with text and links. Clicking anywhere in the
19544 * content area would normally start the drag operation. Use this method
19545 * to specify that an element inside of the content div is the element
19546 * that starts the drag operation.
19547 * @method setHandleElId
19548 * @param id {string} the id of the element that will be used to
19549 * initiate the drag.
19551 setHandleElId: function(id) {
19552 if (typeof id !== "string") {
19555 this.handleElId = id;
19556 this.DDM.regHandle(this.id, id);
19560 * Allows you to set an element outside of the linked element as a drag
19562 * @method setOuterHandleElId
19563 * @param id the id of the element that will be used to initiate the drag
19565 setOuterHandleElId: function(id) {
19566 if (typeof id !== "string") {
19569 Event.on(id, "mousedown",
19570 this.handleMouseDown, this);
19571 this.setHandleElId(id);
19573 this.hasOuterHandles = true;
19577 * Remove all drag and drop hooks for this element
19580 unreg: function() {
19581 Event.un(this.id, "mousedown",
19582 this.handleMouseDown);
19583 Event.un(this.id, "touchstart",
19584 this.handleMouseDown);
19585 this._domRef = null;
19586 this.DDM._remove(this);
19589 destroy : function(){
19594 * Returns true if this instance is locked, or the drag drop mgr is locked
19595 * (meaning that all drag/drop is disabled on the page.)
19597 * @return {boolean} true if this obj or all drag/drop is locked, else
19600 isLocked: function() {
19601 return (this.DDM.isLocked() || this.locked);
19605 * Fired when this object is clicked
19606 * @method handleMouseDown
19608 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19611 handleMouseDown: function(e, oDD){
19613 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19614 //Roo.log('not touch/ button !=0');
19617 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19618 return; // double touch..
19622 if (this.isLocked()) {
19623 //Roo.log('locked');
19627 this.DDM.refreshCache(this.groups);
19628 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19629 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19630 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19631 //Roo.log('no outer handes or not over target');
19634 // Roo.log('check validator');
19635 if (this.clickValidator(e)) {
19636 // Roo.log('validate success');
19637 // set the initial element position
19638 this.setStartPosition();
19641 this.b4MouseDown(e);
19642 this.onMouseDown(e);
19644 this.DDM.handleMouseDown(e, this);
19646 this.DDM.stopEvent(e);
19654 clickValidator: function(e) {
19655 var target = e.getTarget();
19656 return ( this.isValidHandleChild(target) &&
19657 (this.id == this.handleElId ||
19658 this.DDM.handleWasClicked(target, this.id)) );
19662 * Allows you to specify a tag name that should not start a drag operation
19663 * when clicked. This is designed to facilitate embedding links within a
19664 * drag handle that do something other than start the drag.
19665 * @method addInvalidHandleType
19666 * @param {string} tagName the type of element to exclude
19668 addInvalidHandleType: function(tagName) {
19669 var type = tagName.toUpperCase();
19670 this.invalidHandleTypes[type] = type;
19674 * Lets you to specify an element id for a child of a drag handle
19675 * that should not initiate a drag
19676 * @method addInvalidHandleId
19677 * @param {string} id the element id of the element you wish to ignore
19679 addInvalidHandleId: function(id) {
19680 if (typeof id !== "string") {
19683 this.invalidHandleIds[id] = id;
19687 * Lets you specify a css class of elements that will not initiate a drag
19688 * @method addInvalidHandleClass
19689 * @param {string} cssClass the class of the elements you wish to ignore
19691 addInvalidHandleClass: function(cssClass) {
19692 this.invalidHandleClasses.push(cssClass);
19696 * Unsets an excluded tag name set by addInvalidHandleType
19697 * @method removeInvalidHandleType
19698 * @param {string} tagName the type of element to unexclude
19700 removeInvalidHandleType: function(tagName) {
19701 var type = tagName.toUpperCase();
19702 // this.invalidHandleTypes[type] = null;
19703 delete this.invalidHandleTypes[type];
19707 * Unsets an invalid handle id
19708 * @method removeInvalidHandleId
19709 * @param {string} id the id of the element to re-enable
19711 removeInvalidHandleId: function(id) {
19712 if (typeof id !== "string") {
19715 delete this.invalidHandleIds[id];
19719 * Unsets an invalid css class
19720 * @method removeInvalidHandleClass
19721 * @param {string} cssClass the class of the element(s) you wish to
19724 removeInvalidHandleClass: function(cssClass) {
19725 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19726 if (this.invalidHandleClasses[i] == cssClass) {
19727 delete this.invalidHandleClasses[i];
19733 * Checks the tag exclusion list to see if this click should be ignored
19734 * @method isValidHandleChild
19735 * @param {HTMLElement} node the HTMLElement to evaluate
19736 * @return {boolean} true if this is a valid tag type, false if not
19738 isValidHandleChild: function(node) {
19741 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19744 nodeName = node.nodeName.toUpperCase();
19746 nodeName = node.nodeName;
19748 valid = valid && !this.invalidHandleTypes[nodeName];
19749 valid = valid && !this.invalidHandleIds[node.id];
19751 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19752 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19761 * Create the array of horizontal tick marks if an interval was specified
19762 * in setXConstraint().
19763 * @method setXTicks
19766 setXTicks: function(iStartX, iTickSize) {
19768 this.xTickSize = iTickSize;
19772 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19774 this.xTicks[this.xTicks.length] = i;
19779 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19781 this.xTicks[this.xTicks.length] = i;
19786 this.xTicks.sort(this.DDM.numericSort) ;
19790 * Create the array of vertical tick marks if an interval was specified in
19791 * setYConstraint().
19792 * @method setYTicks
19795 setYTicks: function(iStartY, iTickSize) {
19797 this.yTickSize = iTickSize;
19801 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19803 this.yTicks[this.yTicks.length] = i;
19808 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19810 this.yTicks[this.yTicks.length] = i;
19815 this.yTicks.sort(this.DDM.numericSort) ;
19819 * By default, the element can be dragged any place on the screen. Use
19820 * this method to limit the horizontal travel of the element. Pass in
19821 * 0,0 for the parameters if you want to lock the drag to the y axis.
19822 * @method setXConstraint
19823 * @param {int} iLeft the number of pixels the element can move to the left
19824 * @param {int} iRight the number of pixels the element can move to the
19826 * @param {int} iTickSize optional parameter for specifying that the
19828 * should move iTickSize pixels at a time.
19830 setXConstraint: function(iLeft, iRight, iTickSize) {
19831 this.leftConstraint = iLeft;
19832 this.rightConstraint = iRight;
19834 this.minX = this.initPageX - iLeft;
19835 this.maxX = this.initPageX + iRight;
19836 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19838 this.constrainX = true;
19842 * Clears any constraints applied to this instance. Also clears ticks
19843 * since they can't exist independent of a constraint at this time.
19844 * @method clearConstraints
19846 clearConstraints: function() {
19847 this.constrainX = false;
19848 this.constrainY = false;
19853 * Clears any tick interval defined for this instance
19854 * @method clearTicks
19856 clearTicks: function() {
19857 this.xTicks = null;
19858 this.yTicks = null;
19859 this.xTickSize = 0;
19860 this.yTickSize = 0;
19864 * By default, the element can be dragged any place on the screen. Set
19865 * this to limit the vertical travel of the element. Pass in 0,0 for the
19866 * parameters if you want to lock the drag to the x axis.
19867 * @method setYConstraint
19868 * @param {int} iUp the number of pixels the element can move up
19869 * @param {int} iDown the number of pixels the element can move down
19870 * @param {int} iTickSize optional parameter for specifying that the
19871 * element should move iTickSize pixels at a time.
19873 setYConstraint: function(iUp, iDown, iTickSize) {
19874 this.topConstraint = iUp;
19875 this.bottomConstraint = iDown;
19877 this.minY = this.initPageY - iUp;
19878 this.maxY = this.initPageY + iDown;
19879 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19881 this.constrainY = true;
19886 * resetConstraints must be called if you manually reposition a dd element.
19887 * @method resetConstraints
19888 * @param {boolean} maintainOffset
19890 resetConstraints: function() {
19893 // Maintain offsets if necessary
19894 if (this.initPageX || this.initPageX === 0) {
19895 // figure out how much this thing has moved
19896 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19897 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19899 this.setInitPosition(dx, dy);
19901 // This is the first time we have detected the element's position
19903 this.setInitPosition();
19906 if (this.constrainX) {
19907 this.setXConstraint( this.leftConstraint,
19908 this.rightConstraint,
19912 if (this.constrainY) {
19913 this.setYConstraint( this.topConstraint,
19914 this.bottomConstraint,
19920 * Normally the drag element is moved pixel by pixel, but we can specify
19921 * that it move a number of pixels at a time. This method resolves the
19922 * location when we have it set up like this.
19924 * @param {int} val where we want to place the object
19925 * @param {int[]} tickArray sorted array of valid points
19926 * @return {int} the closest tick
19929 getTick: function(val, tickArray) {
19932 // If tick interval is not defined, it is effectively 1 pixel,
19933 // so we return the value passed to us.
19935 } else if (tickArray[0] >= val) {
19936 // The value is lower than the first tick, so we return the first
19938 return tickArray[0];
19940 for (var i=0, len=tickArray.length; i<len; ++i) {
19942 if (tickArray[next] && tickArray[next] >= val) {
19943 var diff1 = val - tickArray[i];
19944 var diff2 = tickArray[next] - val;
19945 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19949 // The value is larger than the last tick, so we return the last
19951 return tickArray[tickArray.length - 1];
19958 * @return {string} string representation of the dd obj
19960 toString: function() {
19961 return ("DragDrop " + this.id);
19969 * Ext JS Library 1.1.1
19970 * Copyright(c) 2006-2007, Ext JS, LLC.
19972 * Originally Released Under LGPL - original licence link has changed is not relivant.
19975 * <script type="text/javascript">
19980 * The drag and drop utility provides a framework for building drag and drop
19981 * applications. In addition to enabling drag and drop for specific elements,
19982 * the drag and drop elements are tracked by the manager class, and the
19983 * interactions between the various elements are tracked during the drag and
19984 * the implementing code is notified about these important moments.
19987 // Only load the library once. Rewriting the manager class would orphan
19988 // existing drag and drop instances.
19989 if (!Roo.dd.DragDropMgr) {
19992 * @class Roo.dd.DragDropMgr
19993 * DragDropMgr is a singleton that tracks the element interaction for
19994 * all DragDrop items in the window. Generally, you will not call
19995 * this class directly, but it does have helper methods that could
19996 * be useful in your DragDrop implementations.
19999 Roo.dd.DragDropMgr = function() {
20001 var Event = Roo.EventManager;
20006 * Two dimensional Array of registered DragDrop objects. The first
20007 * dimension is the DragDrop item group, the second the DragDrop
20010 * @type {string: string}
20017 * Array of element ids defined as drag handles. Used to determine
20018 * if the element that generated the mousedown event is actually the
20019 * handle and not the html element itself.
20020 * @property handleIds
20021 * @type {string: string}
20028 * the DragDrop object that is currently being dragged
20029 * @property dragCurrent
20037 * the DragDrop object(s) that are being hovered over
20038 * @property dragOvers
20046 * the X distance between the cursor and the object being dragged
20055 * the Y distance between the cursor and the object being dragged
20064 * Flag to determine if we should prevent the default behavior of the
20065 * events we define. By default this is true, but this can be set to
20066 * false if you need the default behavior (not recommended)
20067 * @property preventDefault
20071 preventDefault: true,
20074 * Flag to determine if we should stop the propagation of the events
20075 * we generate. This is true by default but you may want to set it to
20076 * false if the html element contains other features that require the
20078 * @property stopPropagation
20082 stopPropagation: true,
20085 * Internal flag that is set to true when drag and drop has been
20087 * @property initialized
20094 * All drag and drop can be disabled.
20102 * Called the first time an element is registered.
20108 this.initialized = true;
20112 * In point mode, drag and drop interaction is defined by the
20113 * location of the cursor during the drag/drop
20121 * In intersect mode, drag and drop interactio nis defined by the
20122 * overlap of two or more drag and drop objects.
20123 * @property INTERSECT
20130 * The current drag and drop mode. Default: POINT
20138 * Runs method on all drag and drop objects
20139 * @method _execOnAll
20143 _execOnAll: function(sMethod, args) {
20144 for (var i in this.ids) {
20145 for (var j in this.ids[i]) {
20146 var oDD = this.ids[i][j];
20147 if (! this.isTypeOfDD(oDD)) {
20150 oDD[sMethod].apply(oDD, args);
20156 * Drag and drop initialization. Sets up the global event handlers
20161 _onLoad: function() {
20165 if (!Roo.isTouch) {
20166 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20167 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20169 Event.on(document, "touchend", this.handleMouseUp, this, true);
20170 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20172 Event.on(window, "unload", this._onUnload, this, true);
20173 Event.on(window, "resize", this._onResize, this, true);
20174 // Event.on(window, "mouseout", this._test);
20179 * Reset constraints on all drag and drop objs
20180 * @method _onResize
20184 _onResize: function(e) {
20185 this._execOnAll("resetConstraints", []);
20189 * Lock all drag and drop functionality
20193 lock: function() { this.locked = true; },
20196 * Unlock all drag and drop functionality
20200 unlock: function() { this.locked = false; },
20203 * Is drag and drop locked?
20205 * @return {boolean} True if drag and drop is locked, false otherwise.
20208 isLocked: function() { return this.locked; },
20211 * Location cache that is set for all drag drop objects when a drag is
20212 * initiated, cleared when the drag is finished.
20213 * @property locationCache
20220 * Set useCache to false if you want to force object the lookup of each
20221 * drag and drop linked element constantly during a drag.
20222 * @property useCache
20229 * The number of pixels that the mouse needs to move after the
20230 * mousedown before the drag is initiated. Default=3;
20231 * @property clickPixelThresh
20235 clickPixelThresh: 3,
20238 * The number of milliseconds after the mousedown event to initiate the
20239 * drag if we don't get a mouseup event. Default=1000
20240 * @property clickTimeThresh
20244 clickTimeThresh: 350,
20247 * Flag that indicates that either the drag pixel threshold or the
20248 * mousdown time threshold has been met
20249 * @property dragThreshMet
20254 dragThreshMet: false,
20257 * Timeout used for the click time threshold
20258 * @property clickTimeout
20263 clickTimeout: null,
20266 * The X position of the mousedown event stored for later use when a
20267 * drag threshold is met.
20276 * The Y position of the mousedown event stored for later use when a
20277 * drag threshold is met.
20286 * Each DragDrop instance must be registered with the DragDropMgr.
20287 * This is executed in DragDrop.init()
20288 * @method regDragDrop
20289 * @param {DragDrop} oDD the DragDrop object to register
20290 * @param {String} sGroup the name of the group this element belongs to
20293 regDragDrop: function(oDD, sGroup) {
20294 if (!this.initialized) { this.init(); }
20296 if (!this.ids[sGroup]) {
20297 this.ids[sGroup] = {};
20299 this.ids[sGroup][oDD.id] = oDD;
20303 * Removes the supplied dd instance from the supplied group. Executed
20304 * by DragDrop.removeFromGroup, so don't call this function directly.
20305 * @method removeDDFromGroup
20309 removeDDFromGroup: function(oDD, sGroup) {
20310 if (!this.ids[sGroup]) {
20311 this.ids[sGroup] = {};
20314 var obj = this.ids[sGroup];
20315 if (obj && obj[oDD.id]) {
20316 delete obj[oDD.id];
20321 * Unregisters a drag and drop item. This is executed in
20322 * DragDrop.unreg, use that method instead of calling this directly.
20327 _remove: function(oDD) {
20328 for (var g in oDD.groups) {
20329 if (g && this.ids[g][oDD.id]) {
20330 delete this.ids[g][oDD.id];
20333 delete this.handleIds[oDD.id];
20337 * Each DragDrop handle element must be registered. This is done
20338 * automatically when executing DragDrop.setHandleElId()
20339 * @method regHandle
20340 * @param {String} sDDId the DragDrop id this element is a handle for
20341 * @param {String} sHandleId the id of the element that is the drag
20345 regHandle: function(sDDId, sHandleId) {
20346 if (!this.handleIds[sDDId]) {
20347 this.handleIds[sDDId] = {};
20349 this.handleIds[sDDId][sHandleId] = sHandleId;
20353 * Utility function to determine if a given element has been
20354 * registered as a drag drop item.
20355 * @method isDragDrop
20356 * @param {String} id the element id to check
20357 * @return {boolean} true if this element is a DragDrop item,
20361 isDragDrop: function(id) {
20362 return ( this.getDDById(id) ) ? true : false;
20366 * Returns the drag and drop instances that are in all groups the
20367 * passed in instance belongs to.
20368 * @method getRelated
20369 * @param {DragDrop} p_oDD the obj to get related data for
20370 * @param {boolean} bTargetsOnly if true, only return targetable objs
20371 * @return {DragDrop[]} the related instances
20374 getRelated: function(p_oDD, bTargetsOnly) {
20376 for (var i in p_oDD.groups) {
20377 for (j in this.ids[i]) {
20378 var dd = this.ids[i][j];
20379 if (! this.isTypeOfDD(dd)) {
20382 if (!bTargetsOnly || dd.isTarget) {
20383 oDDs[oDDs.length] = dd;
20392 * Returns true if the specified dd target is a legal target for
20393 * the specifice drag obj
20394 * @method isLegalTarget
20395 * @param {DragDrop} the drag obj
20396 * @param {DragDrop} the target
20397 * @return {boolean} true if the target is a legal target for the
20401 isLegalTarget: function (oDD, oTargetDD) {
20402 var targets = this.getRelated(oDD, true);
20403 for (var i=0, len=targets.length;i<len;++i) {
20404 if (targets[i].id == oTargetDD.id) {
20413 * My goal is to be able to transparently determine if an object is
20414 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20415 * returns "object", oDD.constructor.toString() always returns
20416 * "DragDrop" and not the name of the subclass. So for now it just
20417 * evaluates a well-known variable in DragDrop.
20418 * @method isTypeOfDD
20419 * @param {Object} the object to evaluate
20420 * @return {boolean} true if typeof oDD = DragDrop
20423 isTypeOfDD: function (oDD) {
20424 return (oDD && oDD.__ygDragDrop);
20428 * Utility function to determine if a given element has been
20429 * registered as a drag drop handle for the given Drag Drop object.
20431 * @param {String} id the element id to check
20432 * @return {boolean} true if this element is a DragDrop handle, false
20436 isHandle: function(sDDId, sHandleId) {
20437 return ( this.handleIds[sDDId] &&
20438 this.handleIds[sDDId][sHandleId] );
20442 * Returns the DragDrop instance for a given id
20443 * @method getDDById
20444 * @param {String} id the id of the DragDrop object
20445 * @return {DragDrop} the drag drop object, null if it is not found
20448 getDDById: function(id) {
20449 for (var i in this.ids) {
20450 if (this.ids[i][id]) {
20451 return this.ids[i][id];
20458 * Fired after a registered DragDrop object gets the mousedown event.
20459 * Sets up the events required to track the object being dragged
20460 * @method handleMouseDown
20461 * @param {Event} e the event
20462 * @param oDD the DragDrop object being dragged
20466 handleMouseDown: function(e, oDD) {
20468 Roo.QuickTips.disable();
20470 this.currentTarget = e.getTarget();
20472 this.dragCurrent = oDD;
20474 var el = oDD.getEl();
20476 // track start position
20477 this.startX = e.getPageX();
20478 this.startY = e.getPageY();
20480 this.deltaX = this.startX - el.offsetLeft;
20481 this.deltaY = this.startY - el.offsetTop;
20483 this.dragThreshMet = false;
20485 this.clickTimeout = setTimeout(
20487 var DDM = Roo.dd.DDM;
20488 DDM.startDrag(DDM.startX, DDM.startY);
20490 this.clickTimeThresh );
20494 * Fired when either the drag pixel threshol or the mousedown hold
20495 * time threshold has been met.
20496 * @method startDrag
20497 * @param x {int} the X position of the original mousedown
20498 * @param y {int} the Y position of the original mousedown
20501 startDrag: function(x, y) {
20502 clearTimeout(this.clickTimeout);
20503 if (this.dragCurrent) {
20504 this.dragCurrent.b4StartDrag(x, y);
20505 this.dragCurrent.startDrag(x, y);
20507 this.dragThreshMet = true;
20511 * Internal function to handle the mouseup event. Will be invoked
20512 * from the context of the document.
20513 * @method handleMouseUp
20514 * @param {Event} e the event
20518 handleMouseUp: function(e) {
20521 Roo.QuickTips.enable();
20523 if (! this.dragCurrent) {
20527 clearTimeout(this.clickTimeout);
20529 if (this.dragThreshMet) {
20530 this.fireEvents(e, true);
20540 * Utility to stop event propagation and event default, if these
20541 * features are turned on.
20542 * @method stopEvent
20543 * @param {Event} e the event as returned by this.getEvent()
20546 stopEvent: function(e){
20547 if(this.stopPropagation) {
20548 e.stopPropagation();
20551 if (this.preventDefault) {
20552 e.preventDefault();
20557 * Internal function to clean up event handlers after the drag
20558 * operation is complete
20560 * @param {Event} e the event
20564 stopDrag: function(e) {
20565 // Fire the drag end event for the item that was dragged
20566 if (this.dragCurrent) {
20567 if (this.dragThreshMet) {
20568 this.dragCurrent.b4EndDrag(e);
20569 this.dragCurrent.endDrag(e);
20572 this.dragCurrent.onMouseUp(e);
20575 this.dragCurrent = null;
20576 this.dragOvers = {};
20580 * Internal function to handle the mousemove event. Will be invoked
20581 * from the context of the html element.
20583 * @TODO figure out what we can do about mouse events lost when the
20584 * user drags objects beyond the window boundary. Currently we can
20585 * detect this in internet explorer by verifying that the mouse is
20586 * down during the mousemove event. Firefox doesn't give us the
20587 * button state on the mousemove event.
20588 * @method handleMouseMove
20589 * @param {Event} e the event
20593 handleMouseMove: function(e) {
20594 if (! this.dragCurrent) {
20598 // var button = e.which || e.button;
20600 // check for IE mouseup outside of page boundary
20601 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20603 return this.handleMouseUp(e);
20606 if (!this.dragThreshMet) {
20607 var diffX = Math.abs(this.startX - e.getPageX());
20608 var diffY = Math.abs(this.startY - e.getPageY());
20609 if (diffX > this.clickPixelThresh ||
20610 diffY > this.clickPixelThresh) {
20611 this.startDrag(this.startX, this.startY);
20615 if (this.dragThreshMet) {
20616 this.dragCurrent.b4Drag(e);
20617 this.dragCurrent.onDrag(e);
20618 if(!this.dragCurrent.moveOnly){
20619 this.fireEvents(e, false);
20629 * Iterates over all of the DragDrop elements to find ones we are
20630 * hovering over or dropping on
20631 * @method fireEvents
20632 * @param {Event} e the event
20633 * @param {boolean} isDrop is this a drop op or a mouseover op?
20637 fireEvents: function(e, isDrop) {
20638 var dc = this.dragCurrent;
20640 // If the user did the mouse up outside of the window, we could
20641 // get here even though we have ended the drag.
20642 if (!dc || dc.isLocked()) {
20646 var pt = e.getPoint();
20648 // cache the previous dragOver array
20654 var enterEvts = [];
20656 // Check to see if the object(s) we were hovering over is no longer
20657 // being hovered over so we can fire the onDragOut event
20658 for (var i in this.dragOvers) {
20660 var ddo = this.dragOvers[i];
20662 if (! this.isTypeOfDD(ddo)) {
20666 if (! this.isOverTarget(pt, ddo, this.mode)) {
20667 outEvts.push( ddo );
20670 oldOvers[i] = true;
20671 delete this.dragOvers[i];
20674 for (var sGroup in dc.groups) {
20676 if ("string" != typeof sGroup) {
20680 for (i in this.ids[sGroup]) {
20681 var oDD = this.ids[sGroup][i];
20682 if (! this.isTypeOfDD(oDD)) {
20686 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20687 if (this.isOverTarget(pt, oDD, this.mode)) {
20688 // look for drop interactions
20690 dropEvts.push( oDD );
20691 // look for drag enter and drag over interactions
20694 // initial drag over: dragEnter fires
20695 if (!oldOvers[oDD.id]) {
20696 enterEvts.push( oDD );
20697 // subsequent drag overs: dragOver fires
20699 overEvts.push( oDD );
20702 this.dragOvers[oDD.id] = oDD;
20710 if (outEvts.length) {
20711 dc.b4DragOut(e, outEvts);
20712 dc.onDragOut(e, outEvts);
20715 if (enterEvts.length) {
20716 dc.onDragEnter(e, enterEvts);
20719 if (overEvts.length) {
20720 dc.b4DragOver(e, overEvts);
20721 dc.onDragOver(e, overEvts);
20724 if (dropEvts.length) {
20725 dc.b4DragDrop(e, dropEvts);
20726 dc.onDragDrop(e, dropEvts);
20730 // fire dragout events
20732 for (i=0, len=outEvts.length; i<len; ++i) {
20733 dc.b4DragOut(e, outEvts[i].id);
20734 dc.onDragOut(e, outEvts[i].id);
20737 // fire enter events
20738 for (i=0,len=enterEvts.length; i<len; ++i) {
20739 // dc.b4DragEnter(e, oDD.id);
20740 dc.onDragEnter(e, enterEvts[i].id);
20743 // fire over events
20744 for (i=0,len=overEvts.length; i<len; ++i) {
20745 dc.b4DragOver(e, overEvts[i].id);
20746 dc.onDragOver(e, overEvts[i].id);
20749 // fire drop events
20750 for (i=0, len=dropEvts.length; i<len; ++i) {
20751 dc.b4DragDrop(e, dropEvts[i].id);
20752 dc.onDragDrop(e, dropEvts[i].id);
20757 // notify about a drop that did not find a target
20758 if (isDrop && !dropEvts.length) {
20759 dc.onInvalidDrop(e);
20765 * Helper function for getting the best match from the list of drag
20766 * and drop objects returned by the drag and drop events when we are
20767 * in INTERSECT mode. It returns either the first object that the
20768 * cursor is over, or the object that has the greatest overlap with
20769 * the dragged element.
20770 * @method getBestMatch
20771 * @param {DragDrop[]} dds The array of drag and drop objects
20773 * @return {DragDrop} The best single match
20776 getBestMatch: function(dds) {
20778 // Return null if the input is not what we expect
20779 //if (!dds || !dds.length || dds.length == 0) {
20781 // If there is only one item, it wins
20782 //} else if (dds.length == 1) {
20784 var len = dds.length;
20789 // Loop through the targeted items
20790 for (var i=0; i<len; ++i) {
20792 // If the cursor is over the object, it wins. If the
20793 // cursor is over multiple matches, the first one we come
20795 if (dd.cursorIsOver) {
20798 // Otherwise the object with the most overlap wins
20801 winner.overlap.getArea() < dd.overlap.getArea()) {
20812 * Refreshes the cache of the top-left and bottom-right points of the
20813 * drag and drop objects in the specified group(s). This is in the
20814 * format that is stored in the drag and drop instance, so typical
20817 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20821 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20823 * @TODO this really should be an indexed array. Alternatively this
20824 * method could accept both.
20825 * @method refreshCache
20826 * @param {Object} groups an associative array of groups to refresh
20829 refreshCache: function(groups) {
20830 for (var sGroup in groups) {
20831 if ("string" != typeof sGroup) {
20834 for (var i in this.ids[sGroup]) {
20835 var oDD = this.ids[sGroup][i];
20837 if (this.isTypeOfDD(oDD)) {
20838 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20839 var loc = this.getLocation(oDD);
20841 this.locationCache[oDD.id] = loc;
20843 delete this.locationCache[oDD.id];
20844 // this will unregister the drag and drop object if
20845 // the element is not in a usable state
20854 * This checks to make sure an element exists and is in the DOM. The
20855 * main purpose is to handle cases where innerHTML is used to remove
20856 * drag and drop objects from the DOM. IE provides an 'unspecified
20857 * error' when trying to access the offsetParent of such an element
20859 * @param {HTMLElement} el the element to check
20860 * @return {boolean} true if the element looks usable
20863 verifyEl: function(el) {
20868 parent = el.offsetParent;
20871 parent = el.offsetParent;
20882 * Returns a Region object containing the drag and drop element's position
20883 * and size, including the padding configured for it
20884 * @method getLocation
20885 * @param {DragDrop} oDD the drag and drop object to get the
20887 * @return {Roo.lib.Region} a Region object representing the total area
20888 * the element occupies, including any padding
20889 * the instance is configured for.
20892 getLocation: function(oDD) {
20893 if (! this.isTypeOfDD(oDD)) {
20897 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20900 pos= Roo.lib.Dom.getXY(el);
20908 x2 = x1 + el.offsetWidth;
20910 y2 = y1 + el.offsetHeight;
20912 t = y1 - oDD.padding[0];
20913 r = x2 + oDD.padding[1];
20914 b = y2 + oDD.padding[2];
20915 l = x1 - oDD.padding[3];
20917 return new Roo.lib.Region( t, r, b, l );
20921 * Checks the cursor location to see if it over the target
20922 * @method isOverTarget
20923 * @param {Roo.lib.Point} pt The point to evaluate
20924 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20925 * @return {boolean} true if the mouse is over the target
20929 isOverTarget: function(pt, oTarget, intersect) {
20930 // use cache if available
20931 var loc = this.locationCache[oTarget.id];
20932 if (!loc || !this.useCache) {
20933 loc = this.getLocation(oTarget);
20934 this.locationCache[oTarget.id] = loc;
20942 oTarget.cursorIsOver = loc.contains( pt );
20944 // DragDrop is using this as a sanity check for the initial mousedown
20945 // in this case we are done. In POINT mode, if the drag obj has no
20946 // contraints, we are also done. Otherwise we need to evaluate the
20947 // location of the target as related to the actual location of the
20948 // dragged element.
20949 var dc = this.dragCurrent;
20950 if (!dc || !dc.getTargetCoord ||
20951 (!intersect && !dc.constrainX && !dc.constrainY)) {
20952 return oTarget.cursorIsOver;
20955 oTarget.overlap = null;
20957 // Get the current location of the drag element, this is the
20958 // location of the mouse event less the delta that represents
20959 // where the original mousedown happened on the element. We
20960 // need to consider constraints and ticks as well.
20961 var pos = dc.getTargetCoord(pt.x, pt.y);
20963 var el = dc.getDragEl();
20964 var curRegion = new Roo.lib.Region( pos.y,
20965 pos.x + el.offsetWidth,
20966 pos.y + el.offsetHeight,
20969 var overlap = curRegion.intersect(loc);
20972 oTarget.overlap = overlap;
20973 return (intersect) ? true : oTarget.cursorIsOver;
20980 * unload event handler
20981 * @method _onUnload
20985 _onUnload: function(e, me) {
20986 Roo.dd.DragDropMgr.unregAll();
20990 * Cleans up the drag and drop events and objects.
20995 unregAll: function() {
20997 if (this.dragCurrent) {
20999 this.dragCurrent = null;
21002 this._execOnAll("unreg", []);
21004 for (i in this.elementCache) {
21005 delete this.elementCache[i];
21008 this.elementCache = {};
21013 * A cache of DOM elements
21014 * @property elementCache
21021 * Get the wrapper for the DOM element specified
21022 * @method getElWrapper
21023 * @param {String} id the id of the element to get
21024 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21026 * @deprecated This wrapper isn't that useful
21029 getElWrapper: function(id) {
21030 var oWrapper = this.elementCache[id];
21031 if (!oWrapper || !oWrapper.el) {
21032 oWrapper = this.elementCache[id] =
21033 new this.ElementWrapper(Roo.getDom(id));
21039 * Returns the actual DOM element
21040 * @method getElement
21041 * @param {String} id the id of the elment to get
21042 * @return {Object} The element
21043 * @deprecated use Roo.getDom instead
21046 getElement: function(id) {
21047 return Roo.getDom(id);
21051 * Returns the style property for the DOM element (i.e.,
21052 * document.getElById(id).style)
21054 * @param {String} id the id of the elment to get
21055 * @return {Object} The style property of the element
21056 * @deprecated use Roo.getDom instead
21059 getCss: function(id) {
21060 var el = Roo.getDom(id);
21061 return (el) ? el.style : null;
21065 * Inner class for cached elements
21066 * @class DragDropMgr.ElementWrapper
21071 ElementWrapper: function(el) {
21076 this.el = el || null;
21081 this.id = this.el && el.id;
21083 * A reference to the style property
21086 this.css = this.el && el.style;
21090 * Returns the X position of an html element
21092 * @param el the element for which to get the position
21093 * @return {int} the X coordinate
21095 * @deprecated use Roo.lib.Dom.getX instead
21098 getPosX: function(el) {
21099 return Roo.lib.Dom.getX(el);
21103 * Returns the Y position of an html element
21105 * @param el the element for which to get the position
21106 * @return {int} the Y coordinate
21107 * @deprecated use Roo.lib.Dom.getY instead
21110 getPosY: function(el) {
21111 return Roo.lib.Dom.getY(el);
21115 * Swap two nodes. In IE, we use the native method, for others we
21116 * emulate the IE behavior
21118 * @param n1 the first node to swap
21119 * @param n2 the other node to swap
21122 swapNode: function(n1, n2) {
21126 var p = n2.parentNode;
21127 var s = n2.nextSibling;
21130 p.insertBefore(n1, n2);
21131 } else if (n2 == n1.nextSibling) {
21132 p.insertBefore(n2, n1);
21134 n1.parentNode.replaceChild(n2, n1);
21135 p.insertBefore(n1, s);
21141 * Returns the current scroll position
21142 * @method getScroll
21146 getScroll: function () {
21147 var t, l, dde=document.documentElement, db=document.body;
21148 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21150 l = dde.scrollLeft;
21157 return { top: t, left: l };
21161 * Returns the specified element style property
21163 * @param {HTMLElement} el the element
21164 * @param {string} styleProp the style property
21165 * @return {string} The value of the style property
21166 * @deprecated use Roo.lib.Dom.getStyle
21169 getStyle: function(el, styleProp) {
21170 return Roo.fly(el).getStyle(styleProp);
21174 * Gets the scrollTop
21175 * @method getScrollTop
21176 * @return {int} the document's scrollTop
21179 getScrollTop: function () { return this.getScroll().top; },
21182 * Gets the scrollLeft
21183 * @method getScrollLeft
21184 * @return {int} the document's scrollTop
21187 getScrollLeft: function () { return this.getScroll().left; },
21190 * Sets the x/y position of an element to the location of the
21193 * @param {HTMLElement} moveEl The element to move
21194 * @param {HTMLElement} targetEl The position reference element
21197 moveToEl: function (moveEl, targetEl) {
21198 var aCoord = Roo.lib.Dom.getXY(targetEl);
21199 Roo.lib.Dom.setXY(moveEl, aCoord);
21203 * Numeric array sort function
21204 * @method numericSort
21207 numericSort: function(a, b) { return (a - b); },
21211 * @property _timeoutCount
21218 * Trying to make the load order less important. Without this we get
21219 * an error if this file is loaded before the Event Utility.
21220 * @method _addListeners
21224 _addListeners: function() {
21225 var DDM = Roo.dd.DDM;
21226 if ( Roo.lib.Event && document ) {
21229 if (DDM._timeoutCount > 2000) {
21231 setTimeout(DDM._addListeners, 10);
21232 if (document && document.body) {
21233 DDM._timeoutCount += 1;
21240 * Recursively searches the immediate parent and all child nodes for
21241 * the handle element in order to determine wheter or not it was
21243 * @method handleWasClicked
21244 * @param node the html element to inspect
21247 handleWasClicked: function(node, id) {
21248 if (this.isHandle(id, node.id)) {
21251 // check to see if this is a text node child of the one we want
21252 var p = node.parentNode;
21255 if (this.isHandle(id, p.id)) {
21270 // shorter alias, save a few bytes
21271 Roo.dd.DDM = Roo.dd.DragDropMgr;
21272 Roo.dd.DDM._addListeners();
21276 * Ext JS Library 1.1.1
21277 * Copyright(c) 2006-2007, Ext JS, LLC.
21279 * Originally Released Under LGPL - original licence link has changed is not relivant.
21282 * <script type="text/javascript">
21287 * A DragDrop implementation where the linked element follows the
21288 * mouse cursor during a drag.
21289 * @extends Roo.dd.DragDrop
21291 * @param {String} id the id of the linked element
21292 * @param {String} sGroup the group of related DragDrop items
21293 * @param {object} config an object containing configurable attributes
21294 * Valid properties for DD:
21297 Roo.dd.DD = function(id, sGroup, config) {
21299 this.init(id, sGroup, config);
21303 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21306 * When set to true, the utility automatically tries to scroll the browser
21307 * window wehn a drag and drop element is dragged near the viewport boundary.
21308 * Defaults to true.
21315 * Sets the pointer offset to the distance between the linked element's top
21316 * left corner and the location the element was clicked
21317 * @method autoOffset
21318 * @param {int} iPageX the X coordinate of the click
21319 * @param {int} iPageY the Y coordinate of the click
21321 autoOffset: function(iPageX, iPageY) {
21322 var x = iPageX - this.startPageX;
21323 var y = iPageY - this.startPageY;
21324 this.setDelta(x, y);
21328 * Sets the pointer offset. You can call this directly to force the
21329 * offset to be in a particular location (e.g., pass in 0,0 to set it
21330 * to the center of the object)
21332 * @param {int} iDeltaX the distance from the left
21333 * @param {int} iDeltaY the distance from the top
21335 setDelta: function(iDeltaX, iDeltaY) {
21336 this.deltaX = iDeltaX;
21337 this.deltaY = iDeltaY;
21341 * Sets the drag element to the location of the mousedown or click event,
21342 * maintaining the cursor location relative to the location on the element
21343 * that was clicked. Override this if you want to place the element in a
21344 * location other than where the cursor is.
21345 * @method setDragElPos
21346 * @param {int} iPageX the X coordinate of the mousedown or drag event
21347 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21349 setDragElPos: function(iPageX, iPageY) {
21350 // the first time we do this, we are going to check to make sure
21351 // the element has css positioning
21353 var el = this.getDragEl();
21354 this.alignElWithMouse(el, iPageX, iPageY);
21358 * Sets the element to the location of the mousedown or click event,
21359 * maintaining the cursor location relative to the location on the element
21360 * that was clicked. Override this if you want to place the element in a
21361 * location other than where the cursor is.
21362 * @method alignElWithMouse
21363 * @param {HTMLElement} el the element to move
21364 * @param {int} iPageX the X coordinate of the mousedown or drag event
21365 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21367 alignElWithMouse: function(el, iPageX, iPageY) {
21368 var oCoord = this.getTargetCoord(iPageX, iPageY);
21369 var fly = el.dom ? el : Roo.fly(el);
21370 if (!this.deltaSetXY) {
21371 var aCoord = [oCoord.x, oCoord.y];
21373 var newLeft = fly.getLeft(true);
21374 var newTop = fly.getTop(true);
21375 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21377 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21380 this.cachePosition(oCoord.x, oCoord.y);
21381 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21386 * Saves the most recent position so that we can reset the constraints and
21387 * tick marks on-demand. We need to know this so that we can calculate the
21388 * number of pixels the element is offset from its original position.
21389 * @method cachePosition
21390 * @param iPageX the current x position (optional, this just makes it so we
21391 * don't have to look it up again)
21392 * @param iPageY the current y position (optional, this just makes it so we
21393 * don't have to look it up again)
21395 cachePosition: function(iPageX, iPageY) {
21397 this.lastPageX = iPageX;
21398 this.lastPageY = iPageY;
21400 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21401 this.lastPageX = aCoord[0];
21402 this.lastPageY = aCoord[1];
21407 * Auto-scroll the window if the dragged object has been moved beyond the
21408 * visible window boundary.
21409 * @method autoScroll
21410 * @param {int} x the drag element's x position
21411 * @param {int} y the drag element's y position
21412 * @param {int} h the height of the drag element
21413 * @param {int} w the width of the drag element
21416 autoScroll: function(x, y, h, w) {
21419 // The client height
21420 var clientH = Roo.lib.Dom.getViewWidth();
21422 // The client width
21423 var clientW = Roo.lib.Dom.getViewHeight();
21425 // The amt scrolled down
21426 var st = this.DDM.getScrollTop();
21428 // The amt scrolled right
21429 var sl = this.DDM.getScrollLeft();
21431 // Location of the bottom of the element
21434 // Location of the right of the element
21437 // The distance from the cursor to the bottom of the visible area,
21438 // adjusted so that we don't scroll if the cursor is beyond the
21439 // element drag constraints
21440 var toBot = (clientH + st - y - this.deltaY);
21442 // The distance from the cursor to the right of the visible area
21443 var toRight = (clientW + sl - x - this.deltaX);
21446 // How close to the edge the cursor must be before we scroll
21447 // var thresh = (document.all) ? 100 : 40;
21450 // How many pixels to scroll per autoscroll op. This helps to reduce
21451 // clunky scrolling. IE is more sensitive about this ... it needs this
21452 // value to be higher.
21453 var scrAmt = (document.all) ? 80 : 30;
21455 // Scroll down if we are near the bottom of the visible page and the
21456 // obj extends below the crease
21457 if ( bot > clientH && toBot < thresh ) {
21458 window.scrollTo(sl, st + scrAmt);
21461 // Scroll up if the window is scrolled down and the top of the object
21462 // goes above the top border
21463 if ( y < st && st > 0 && y - st < thresh ) {
21464 window.scrollTo(sl, st - scrAmt);
21467 // Scroll right if the obj is beyond the right border and the cursor is
21468 // near the border.
21469 if ( right > clientW && toRight < thresh ) {
21470 window.scrollTo(sl + scrAmt, st);
21473 // Scroll left if the window has been scrolled to the right and the obj
21474 // extends past the left border
21475 if ( x < sl && sl > 0 && x - sl < thresh ) {
21476 window.scrollTo(sl - scrAmt, st);
21482 * Finds the location the element should be placed if we want to move
21483 * it to where the mouse location less the click offset would place us.
21484 * @method getTargetCoord
21485 * @param {int} iPageX the X coordinate of the click
21486 * @param {int} iPageY the Y coordinate of the click
21487 * @return an object that contains the coordinates (Object.x and Object.y)
21490 getTargetCoord: function(iPageX, iPageY) {
21493 var x = iPageX - this.deltaX;
21494 var y = iPageY - this.deltaY;
21496 if (this.constrainX) {
21497 if (x < this.minX) { x = this.minX; }
21498 if (x > this.maxX) { x = this.maxX; }
21501 if (this.constrainY) {
21502 if (y < this.minY) { y = this.minY; }
21503 if (y > this.maxY) { y = this.maxY; }
21506 x = this.getTick(x, this.xTicks);
21507 y = this.getTick(y, this.yTicks);
21514 * Sets up config options specific to this class. Overrides
21515 * Roo.dd.DragDrop, but all versions of this method through the
21516 * inheritance chain are called
21518 applyConfig: function() {
21519 Roo.dd.DD.superclass.applyConfig.call(this);
21520 this.scroll = (this.config.scroll !== false);
21524 * Event that fires prior to the onMouseDown event. Overrides
21527 b4MouseDown: function(e) {
21528 // this.resetConstraints();
21529 this.autoOffset(e.getPageX(),
21534 * Event that fires prior to the onDrag event. Overrides
21537 b4Drag: function(e) {
21538 this.setDragElPos(e.getPageX(),
21542 toString: function() {
21543 return ("DD " + this.id);
21546 //////////////////////////////////////////////////////////////////////////
21547 // Debugging ygDragDrop events that can be overridden
21548 //////////////////////////////////////////////////////////////////////////
21550 startDrag: function(x, y) {
21553 onDrag: function(e) {
21556 onDragEnter: function(e, id) {
21559 onDragOver: function(e, id) {
21562 onDragOut: function(e, id) {
21565 onDragDrop: function(e, id) {
21568 endDrag: function(e) {
21575 * Ext JS Library 1.1.1
21576 * Copyright(c) 2006-2007, Ext JS, LLC.
21578 * Originally Released Under LGPL - original licence link has changed is not relivant.
21581 * <script type="text/javascript">
21585 * @class Roo.dd.DDProxy
21586 * A DragDrop implementation that inserts an empty, bordered div into
21587 * the document that follows the cursor during drag operations. At the time of
21588 * the click, the frame div is resized to the dimensions of the linked html
21589 * element, and moved to the exact location of the linked element.
21591 * References to the "frame" element refer to the single proxy element that
21592 * was created to be dragged in place of all DDProxy elements on the
21595 * @extends Roo.dd.DD
21597 * @param {String} id the id of the linked html element
21598 * @param {String} sGroup the group of related DragDrop objects
21599 * @param {object} config an object containing configurable attributes
21600 * Valid properties for DDProxy in addition to those in DragDrop:
21601 * resizeFrame, centerFrame, dragElId
21603 Roo.dd.DDProxy = function(id, sGroup, config) {
21605 this.init(id, sGroup, config);
21611 * The default drag frame div id
21612 * @property Roo.dd.DDProxy.dragElId
21616 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21618 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21621 * By default we resize the drag frame to be the same size as the element
21622 * we want to drag (this is to get the frame effect). We can turn it off
21623 * if we want a different behavior.
21624 * @property resizeFrame
21630 * By default the frame is positioned exactly where the drag element is, so
21631 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21632 * you do not have constraints on the obj is to have the drag frame centered
21633 * around the cursor. Set centerFrame to true for this effect.
21634 * @property centerFrame
21637 centerFrame: false,
21640 * Creates the proxy element if it does not yet exist
21641 * @method createFrame
21643 createFrame: function() {
21645 var body = document.body;
21647 if (!body || !body.firstChild) {
21648 setTimeout( function() { self.createFrame(); }, 50 );
21652 var div = this.getDragEl();
21655 div = document.createElement("div");
21656 div.id = this.dragElId;
21659 s.position = "absolute";
21660 s.visibility = "hidden";
21662 s.border = "2px solid #aaa";
21665 // appendChild can blow up IE if invoked prior to the window load event
21666 // while rendering a table. It is possible there are other scenarios
21667 // that would cause this to happen as well.
21668 body.insertBefore(div, body.firstChild);
21673 * Initialization for the drag frame element. Must be called in the
21674 * constructor of all subclasses
21675 * @method initFrame
21677 initFrame: function() {
21678 this.createFrame();
21681 applyConfig: function() {
21682 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21684 this.resizeFrame = (this.config.resizeFrame !== false);
21685 this.centerFrame = (this.config.centerFrame);
21686 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21690 * Resizes the drag frame to the dimensions of the clicked object, positions
21691 * it over the object, and finally displays it
21692 * @method showFrame
21693 * @param {int} iPageX X click position
21694 * @param {int} iPageY Y click position
21697 showFrame: function(iPageX, iPageY) {
21698 var el = this.getEl();
21699 var dragEl = this.getDragEl();
21700 var s = dragEl.style;
21702 this._resizeProxy();
21704 if (this.centerFrame) {
21705 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21706 Math.round(parseInt(s.height, 10)/2) );
21709 this.setDragElPos(iPageX, iPageY);
21711 Roo.fly(dragEl).show();
21715 * The proxy is automatically resized to the dimensions of the linked
21716 * element when a drag is initiated, unless resizeFrame is set to false
21717 * @method _resizeProxy
21720 _resizeProxy: function() {
21721 if (this.resizeFrame) {
21722 var el = this.getEl();
21723 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21727 // overrides Roo.dd.DragDrop
21728 b4MouseDown: function(e) {
21729 var x = e.getPageX();
21730 var y = e.getPageY();
21731 this.autoOffset(x, y);
21732 this.setDragElPos(x, y);
21735 // overrides Roo.dd.DragDrop
21736 b4StartDrag: function(x, y) {
21737 // show the drag frame
21738 this.showFrame(x, y);
21741 // overrides Roo.dd.DragDrop
21742 b4EndDrag: function(e) {
21743 Roo.fly(this.getDragEl()).hide();
21746 // overrides Roo.dd.DragDrop
21747 // By default we try to move the element to the last location of the frame.
21748 // This is so that the default behavior mirrors that of Roo.dd.DD.
21749 endDrag: function(e) {
21751 var lel = this.getEl();
21752 var del = this.getDragEl();
21754 // Show the drag frame briefly so we can get its position
21755 del.style.visibility = "";
21758 // Hide the linked element before the move to get around a Safari
21760 lel.style.visibility = "hidden";
21761 Roo.dd.DDM.moveToEl(lel, del);
21762 del.style.visibility = "hidden";
21763 lel.style.visibility = "";
21768 beforeMove : function(){
21772 afterDrag : function(){
21776 toString: function() {
21777 return ("DDProxy " + this.id);
21783 * Ext JS Library 1.1.1
21784 * Copyright(c) 2006-2007, Ext JS, LLC.
21786 * Originally Released Under LGPL - original licence link has changed is not relivant.
21789 * <script type="text/javascript">
21793 * @class Roo.dd.DDTarget
21794 * A DragDrop implementation that does not move, but can be a drop
21795 * target. You would get the same result by simply omitting implementation
21796 * for the event callbacks, but this way we reduce the processing cost of the
21797 * event listener and the callbacks.
21798 * @extends Roo.dd.DragDrop
21800 * @param {String} id the id of the element that is a drop target
21801 * @param {String} sGroup the group of related DragDrop objects
21802 * @param {object} config an object containing configurable attributes
21803 * Valid properties for DDTarget in addition to those in
21807 Roo.dd.DDTarget = function(id, sGroup, config) {
21809 this.initTarget(id, sGroup, config);
21811 if (config && (config.listeners || config.events)) {
21812 Roo.dd.DragDrop.superclass.constructor.call(this, {
21813 listeners : config.listeners || {},
21814 events : config.events || {}
21819 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21820 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21821 toString: function() {
21822 return ("DDTarget " + this.id);
21827 * Ext JS Library 1.1.1
21828 * Copyright(c) 2006-2007, Ext JS, LLC.
21830 * Originally Released Under LGPL - original licence link has changed is not relivant.
21833 * <script type="text/javascript">
21838 * @class Roo.dd.ScrollManager
21839 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21840 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21843 Roo.dd.ScrollManager = function(){
21844 var ddm = Roo.dd.DragDropMgr;
21851 var onStop = function(e){
21856 var triggerRefresh = function(){
21857 if(ddm.dragCurrent){
21858 ddm.refreshCache(ddm.dragCurrent.groups);
21862 var doScroll = function(){
21863 if(ddm.dragCurrent){
21864 var dds = Roo.dd.ScrollManager;
21866 if(proc.el.scroll(proc.dir, dds.increment)){
21870 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21875 var clearProc = function(){
21877 clearInterval(proc.id);
21884 var startProc = function(el, dir){
21885 Roo.log('scroll startproc');
21889 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21892 var onFire = function(e, isDrop){
21894 if(isDrop || !ddm.dragCurrent){ return; }
21895 var dds = Roo.dd.ScrollManager;
21896 if(!dragEl || dragEl != ddm.dragCurrent){
21897 dragEl = ddm.dragCurrent;
21898 // refresh regions on drag start
21899 dds.refreshCache();
21902 var xy = Roo.lib.Event.getXY(e);
21903 var pt = new Roo.lib.Point(xy[0], xy[1]);
21904 for(var id in els){
21905 var el = els[id], r = el._region;
21906 if(r && r.contains(pt) && el.isScrollable()){
21907 if(r.bottom - pt.y <= dds.thresh){
21909 startProc(el, "down");
21912 }else if(r.right - pt.x <= dds.thresh){
21914 startProc(el, "left");
21917 }else if(pt.y - r.top <= dds.thresh){
21919 startProc(el, "up");
21922 }else if(pt.x - r.left <= dds.thresh){
21924 startProc(el, "right");
21933 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21934 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21938 * Registers new overflow element(s) to auto scroll
21939 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21941 register : function(el){
21942 if(el instanceof Array){
21943 for(var i = 0, len = el.length; i < len; i++) {
21944 this.register(el[i]);
21950 Roo.dd.ScrollManager.els = els;
21954 * Unregisters overflow element(s) so they are no longer scrolled
21955 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21957 unregister : function(el){
21958 if(el instanceof Array){
21959 for(var i = 0, len = el.length; i < len; i++) {
21960 this.unregister(el[i]);
21969 * The number of pixels from the edge of a container the pointer needs to be to
21970 * trigger scrolling (defaults to 25)
21976 * The number of pixels to scroll in each scroll increment (defaults to 50)
21982 * The frequency of scrolls in milliseconds (defaults to 500)
21988 * True to animate the scroll (defaults to true)
21994 * The animation duration in seconds -
21995 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22001 * Manually trigger a cache refresh.
22003 refreshCache : function(){
22004 for(var id in els){
22005 if(typeof els[id] == 'object'){ // for people extending the object prototype
22006 els[id]._region = els[id].getRegion();
22013 * Ext JS Library 1.1.1
22014 * Copyright(c) 2006-2007, Ext JS, LLC.
22016 * Originally Released Under LGPL - original licence link has changed is not relivant.
22019 * <script type="text/javascript">
22024 * @class Roo.dd.Registry
22025 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
22026 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22029 Roo.dd.Registry = function(){
22032 var autoIdSeed = 0;
22034 var getId = function(el, autogen){
22035 if(typeof el == "string"){
22039 if(!id && autogen !== false){
22040 id = "roodd-" + (++autoIdSeed);
22048 * Register a drag drop element
22049 * @param {String|HTMLElement} element The id or DOM node to register
22050 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22051 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
22052 * knows how to interpret, plus there are some specific properties known to the Registry that should be
22053 * populated in the data object (if applicable):
22055 Value Description<br />
22056 --------- ------------------------------------------<br />
22057 handles Array of DOM nodes that trigger dragging<br />
22058 for the element being registered<br />
22059 isHandle True if the element passed in triggers<br />
22060 dragging itself, else false
22063 register : function(el, data){
22065 if(typeof el == "string"){
22066 el = document.getElementById(el);
22069 elements[getId(el)] = data;
22070 if(data.isHandle !== false){
22071 handles[data.ddel.id] = data;
22074 var hs = data.handles;
22075 for(var i = 0, len = hs.length; i < len; i++){
22076 handles[getId(hs[i])] = data;
22082 * Unregister a drag drop element
22083 * @param {String|HTMLElement} element The id or DOM node to unregister
22085 unregister : function(el){
22086 var id = getId(el, false);
22087 var data = elements[id];
22089 delete elements[id];
22091 var hs = data.handles;
22092 for(var i = 0, len = hs.length; i < len; i++){
22093 delete handles[getId(hs[i], false)];
22100 * Returns the handle registered for a DOM Node by id
22101 * @param {String|HTMLElement} id The DOM node or id to look up
22102 * @return {Object} handle The custom handle data
22104 getHandle : function(id){
22105 if(typeof id != "string"){ // must be element?
22108 return handles[id];
22112 * Returns the handle that is registered for the DOM node that is the target of the event
22113 * @param {Event} e The event
22114 * @return {Object} handle The custom handle data
22116 getHandleFromEvent : function(e){
22117 var t = Roo.lib.Event.getTarget(e);
22118 return t ? handles[t.id] : null;
22122 * Returns a custom data object that is registered for a DOM node by id
22123 * @param {String|HTMLElement} id The DOM node or id to look up
22124 * @return {Object} data The custom data
22126 getTarget : function(id){
22127 if(typeof id != "string"){ // must be element?
22130 return elements[id];
22134 * Returns a custom data object that is registered for the DOM node that is the target of the event
22135 * @param {Event} e The event
22136 * @return {Object} data The custom data
22138 getTargetFromEvent : function(e){
22139 var t = Roo.lib.Event.getTarget(e);
22140 return t ? elements[t.id] || handles[t.id] : null;
22145 * Ext JS Library 1.1.1
22146 * Copyright(c) 2006-2007, Ext JS, LLC.
22148 * Originally Released Under LGPL - original licence link has changed is not relivant.
22151 * <script type="text/javascript">
22156 * @class Roo.dd.StatusProxy
22157 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22158 * default drag proxy used by all Roo.dd components.
22160 * @param {Object} config
22162 Roo.dd.StatusProxy = function(config){
22163 Roo.apply(this, config);
22164 this.id = this.id || Roo.id();
22165 this.el = new Roo.Layer({
22167 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22168 {tag: "div", cls: "x-dd-drop-icon"},
22169 {tag: "div", cls: "x-dd-drag-ghost"}
22172 shadow: !config || config.shadow !== false
22174 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22175 this.dropStatus = this.dropNotAllowed;
22178 Roo.dd.StatusProxy.prototype = {
22180 * @cfg {String} dropAllowed
22181 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22183 dropAllowed : "x-dd-drop-ok",
22185 * @cfg {String} dropNotAllowed
22186 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22188 dropNotAllowed : "x-dd-drop-nodrop",
22191 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22192 * over the current target element.
22193 * @param {String} cssClass The css class for the new drop status indicator image
22195 setStatus : function(cssClass){
22196 cssClass = cssClass || this.dropNotAllowed;
22197 if(this.dropStatus != cssClass){
22198 this.el.replaceClass(this.dropStatus, cssClass);
22199 this.dropStatus = cssClass;
22204 * Resets the status indicator to the default dropNotAllowed value
22205 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22207 reset : function(clearGhost){
22208 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22209 this.dropStatus = this.dropNotAllowed;
22211 this.ghost.update("");
22216 * Updates the contents of the ghost element
22217 * @param {String} html The html that will replace the current innerHTML of the ghost element
22219 update : function(html){
22220 if(typeof html == "string"){
22221 this.ghost.update(html);
22223 this.ghost.update("");
22224 html.style.margin = "0";
22225 this.ghost.dom.appendChild(html);
22227 // ensure float = none set?? cant remember why though.
22228 var el = this.ghost.dom.firstChild;
22230 Roo.fly(el).setStyle('float', 'none');
22235 * Returns the underlying proxy {@link Roo.Layer}
22236 * @return {Roo.Layer} el
22238 getEl : function(){
22243 * Returns the ghost element
22244 * @return {Roo.Element} el
22246 getGhost : function(){
22252 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22254 hide : function(clear){
22262 * Stops the repair animation if it's currently running
22265 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22271 * Displays this proxy
22278 * Force the Layer to sync its shadow and shim positions to the element
22285 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22286 * invalid drop operation by the item being dragged.
22287 * @param {Array} xy The XY position of the element ([x, y])
22288 * @param {Function} callback The function to call after the repair is complete
22289 * @param {Object} scope The scope in which to execute the callback
22291 repair : function(xy, callback, scope){
22292 this.callback = callback;
22293 this.scope = scope;
22294 if(xy && this.animRepair !== false){
22295 this.el.addClass("x-dd-drag-repair");
22296 this.el.hideUnders(true);
22297 this.anim = this.el.shift({
22298 duration: this.repairDuration || .5,
22302 callback: this.afterRepair,
22306 this.afterRepair();
22311 afterRepair : function(){
22313 if(typeof this.callback == "function"){
22314 this.callback.call(this.scope || this);
22316 this.callback = null;
22321 * Ext JS Library 1.1.1
22322 * Copyright(c) 2006-2007, Ext JS, LLC.
22324 * Originally Released Under LGPL - original licence link has changed is not relivant.
22327 * <script type="text/javascript">
22331 * @class Roo.dd.DragSource
22332 * @extends Roo.dd.DDProxy
22333 * A simple class that provides the basic implementation needed to make any element draggable.
22335 * @param {String/HTMLElement/Element} el The container element
22336 * @param {Object} config
22338 Roo.dd.DragSource = function(el, config){
22339 this.el = Roo.get(el);
22340 this.dragData = {};
22342 Roo.apply(this, config);
22345 this.proxy = new Roo.dd.StatusProxy();
22348 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22349 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22351 this.dragging = false;
22354 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22356 * @cfg {String} dropAllowed
22357 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22359 dropAllowed : "x-dd-drop-ok",
22361 * @cfg {String} dropNotAllowed
22362 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22364 dropNotAllowed : "x-dd-drop-nodrop",
22367 * Returns the data object associated with this drag source
22368 * @return {Object} data An object containing arbitrary data
22370 getDragData : function(e){
22371 return this.dragData;
22375 onDragEnter : function(e, id){
22376 var target = Roo.dd.DragDropMgr.getDDById(id);
22377 this.cachedTarget = target;
22378 if(this.beforeDragEnter(target, e, id) !== false){
22379 if(target.isNotifyTarget){
22380 var status = target.notifyEnter(this, e, this.dragData);
22381 this.proxy.setStatus(status);
22383 this.proxy.setStatus(this.dropAllowed);
22386 if(this.afterDragEnter){
22388 * An empty function by default, but provided so that you can perform a custom action
22389 * when the dragged item enters the drop target by providing an implementation.
22390 * @param {Roo.dd.DragDrop} target The drop target
22391 * @param {Event} e The event object
22392 * @param {String} id The id of the dragged element
22393 * @method afterDragEnter
22395 this.afterDragEnter(target, e, id);
22401 * An empty function by default, but provided so that you can perform a custom action
22402 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22403 * @param {Roo.dd.DragDrop} target The drop target
22404 * @param {Event} e The event object
22405 * @param {String} id The id of the dragged element
22406 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22408 beforeDragEnter : function(target, e, id){
22413 alignElWithMouse: function() {
22414 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22419 onDragOver : function(e, id){
22420 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22421 if(this.beforeDragOver(target, e, id) !== false){
22422 if(target.isNotifyTarget){
22423 var status = target.notifyOver(this, e, this.dragData);
22424 this.proxy.setStatus(status);
22427 if(this.afterDragOver){
22429 * An empty function by default, but provided so that you can perform a custom action
22430 * while the dragged item is over the drop target by providing an implementation.
22431 * @param {Roo.dd.DragDrop} target The drop target
22432 * @param {Event} e The event object
22433 * @param {String} id The id of the dragged element
22434 * @method afterDragOver
22436 this.afterDragOver(target, e, id);
22442 * An empty function by default, but provided so that you can perform a custom action
22443 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22444 * @param {Roo.dd.DragDrop} target The drop target
22445 * @param {Event} e The event object
22446 * @param {String} id The id of the dragged element
22447 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22449 beforeDragOver : function(target, e, id){
22454 onDragOut : function(e, id){
22455 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22456 if(this.beforeDragOut(target, e, id) !== false){
22457 if(target.isNotifyTarget){
22458 target.notifyOut(this, e, this.dragData);
22460 this.proxy.reset();
22461 if(this.afterDragOut){
22463 * An empty function by default, but provided so that you can perform a custom action
22464 * after the dragged item is dragged out of the target without dropping.
22465 * @param {Roo.dd.DragDrop} target The drop target
22466 * @param {Event} e The event object
22467 * @param {String} id The id of the dragged element
22468 * @method afterDragOut
22470 this.afterDragOut(target, e, id);
22473 this.cachedTarget = null;
22477 * An empty function by default, but provided so that you can perform a custom action before the dragged
22478 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22479 * @param {Roo.dd.DragDrop} target The drop target
22480 * @param {Event} e The event object
22481 * @param {String} id The id of the dragged element
22482 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22484 beforeDragOut : function(target, e, id){
22489 onDragDrop : function(e, id){
22490 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22491 if(this.beforeDragDrop(target, e, id) !== false){
22492 if(target.isNotifyTarget){
22493 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22494 this.onValidDrop(target, e, id);
22496 this.onInvalidDrop(target, e, id);
22499 this.onValidDrop(target, e, id);
22502 if(this.afterDragDrop){
22504 * An empty function by default, but provided so that you can perform a custom action
22505 * after a valid drag drop has occurred by providing an implementation.
22506 * @param {Roo.dd.DragDrop} target The drop target
22507 * @param {Event} e The event object
22508 * @param {String} id The id of the dropped element
22509 * @method afterDragDrop
22511 this.afterDragDrop(target, e, id);
22514 delete this.cachedTarget;
22518 * An empty function by default, but provided so that you can perform a custom action before the dragged
22519 * item is dropped onto the target and optionally cancel the onDragDrop.
22520 * @param {Roo.dd.DragDrop} target The drop target
22521 * @param {Event} e The event object
22522 * @param {String} id The id of the dragged element
22523 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22525 beforeDragDrop : function(target, e, id){
22530 onValidDrop : function(target, e, id){
22532 if(this.afterValidDrop){
22534 * An empty function by default, but provided so that you can perform a custom action
22535 * after a valid drop has occurred by providing an implementation.
22536 * @param {Object} target The target DD
22537 * @param {Event} e The event object
22538 * @param {String} id The id of the dropped element
22539 * @method afterInvalidDrop
22541 this.afterValidDrop(target, e, id);
22546 getRepairXY : function(e, data){
22547 return this.el.getXY();
22551 onInvalidDrop : function(target, e, id){
22552 this.beforeInvalidDrop(target, e, id);
22553 if(this.cachedTarget){
22554 if(this.cachedTarget.isNotifyTarget){
22555 this.cachedTarget.notifyOut(this, e, this.dragData);
22557 this.cacheTarget = null;
22559 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22561 if(this.afterInvalidDrop){
22563 * An empty function by default, but provided so that you can perform a custom action
22564 * after an invalid drop has occurred by providing an implementation.
22565 * @param {Event} e The event object
22566 * @param {String} id The id of the dropped element
22567 * @method afterInvalidDrop
22569 this.afterInvalidDrop(e, id);
22574 afterRepair : function(){
22576 this.el.highlight(this.hlColor || "c3daf9");
22578 this.dragging = false;
22582 * An empty function by default, but provided so that you can perform a custom action after an invalid
22583 * drop has occurred.
22584 * @param {Roo.dd.DragDrop} target The drop target
22585 * @param {Event} e The event object
22586 * @param {String} id The id of the dragged element
22587 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22589 beforeInvalidDrop : function(target, e, id){
22594 handleMouseDown : function(e){
22595 if(this.dragging) {
22598 var data = this.getDragData(e);
22599 if(data && this.onBeforeDrag(data, e) !== false){
22600 this.dragData = data;
22602 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22607 * An empty function by default, but provided so that you can perform a custom action before the initial
22608 * drag event begins and optionally cancel it.
22609 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22610 * @param {Event} e The event object
22611 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22613 onBeforeDrag : function(data, e){
22618 * An empty function by default, but provided so that you can perform a custom action once the initial
22619 * drag event has begun. The drag cannot be canceled from this function.
22620 * @param {Number} x The x position of the click on the dragged object
22621 * @param {Number} y The y position of the click on the dragged object
22623 onStartDrag : Roo.emptyFn,
22625 // private - YUI override
22626 startDrag : function(x, y){
22627 this.proxy.reset();
22628 this.dragging = true;
22629 this.proxy.update("");
22630 this.onInitDrag(x, y);
22635 onInitDrag : function(x, y){
22636 var clone = this.el.dom.cloneNode(true);
22637 clone.id = Roo.id(); // prevent duplicate ids
22638 this.proxy.update(clone);
22639 this.onStartDrag(x, y);
22644 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22645 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22647 getProxy : function(){
22652 * Hides the drag source's {@link Roo.dd.StatusProxy}
22654 hideProxy : function(){
22656 this.proxy.reset(true);
22657 this.dragging = false;
22661 triggerCacheRefresh : function(){
22662 Roo.dd.DDM.refreshCache(this.groups);
22665 // private - override to prevent hiding
22666 b4EndDrag: function(e) {
22669 // private - override to prevent moving
22670 endDrag : function(e){
22671 this.onEndDrag(this.dragData, e);
22675 onEndDrag : function(data, e){
22678 // private - pin to cursor
22679 autoOffset : function(x, y) {
22680 this.setDelta(-12, -20);
22684 * Ext JS Library 1.1.1
22685 * Copyright(c) 2006-2007, Ext JS, LLC.
22687 * Originally Released Under LGPL - original licence link has changed is not relivant.
22690 * <script type="text/javascript">
22695 * @class Roo.dd.DropTarget
22696 * @extends Roo.dd.DDTarget
22697 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22698 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22700 * @param {String/HTMLElement/Element} el The container element
22701 * @param {Object} config
22703 Roo.dd.DropTarget = function(el, config){
22704 this.el = Roo.get(el);
22706 var listeners = false; ;
22707 if (config && config.listeners) {
22708 listeners= config.listeners;
22709 delete config.listeners;
22711 Roo.apply(this, config);
22713 if(this.containerScroll){
22714 Roo.dd.ScrollManager.register(this.el);
22718 * @scope Roo.dd.DropTarget
22723 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22724 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22725 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22727 * IMPORTANT : it should set this.valid to true|false
22729 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22730 * @param {Event} e The event
22731 * @param {Object} data An object containing arbitrary data supplied by the drag source
22737 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22738 * This method will be called on every mouse movement while the drag source is over the drop target.
22739 * This default implementation simply returns the dropAllowed config value.
22741 * IMPORTANT : it should set this.valid to true|false
22743 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22744 * @param {Event} e The event
22745 * @param {Object} data An object containing arbitrary data supplied by the drag source
22751 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22752 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22753 * overClass (if any) from the drop element.
22756 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22757 * @param {Event} e The event
22758 * @param {Object} data An object containing arbitrary data supplied by the drag source
22764 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22765 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22766 * implementation that does something to process the drop event and returns true so that the drag source's
22767 * repair action does not run.
22769 * IMPORTANT : it should set this.success
22771 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22772 * @param {Event} e The event
22773 * @param {Object} data An object containing arbitrary data supplied by the drag source
22779 Roo.dd.DropTarget.superclass.constructor.call( this,
22781 this.ddGroup || this.group,
22784 listeners : listeners || {}
22792 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22794 * @cfg {String} overClass
22795 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22798 * @cfg {String} ddGroup
22799 * The drag drop group to handle drop events for
22803 * @cfg {String} dropAllowed
22804 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22806 dropAllowed : "x-dd-drop-ok",
22808 * @cfg {String} dropNotAllowed
22809 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22811 dropNotAllowed : "x-dd-drop-nodrop",
22813 * @cfg {boolean} success
22814 * set this after drop listener..
22818 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22819 * if the drop point is valid for over/enter..
22826 isNotifyTarget : true,
22831 notifyEnter : function(dd, e, data)
22834 this.fireEvent('enter', dd, e, data);
22835 if(this.overClass){
22836 this.el.addClass(this.overClass);
22838 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22839 this.valid ? this.dropAllowed : this.dropNotAllowed
22846 notifyOver : function(dd, e, data)
22849 this.fireEvent('over', dd, e, data);
22850 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22851 this.valid ? this.dropAllowed : this.dropNotAllowed
22858 notifyOut : function(dd, e, data)
22860 this.fireEvent('out', dd, e, data);
22861 if(this.overClass){
22862 this.el.removeClass(this.overClass);
22869 notifyDrop : function(dd, e, data)
22871 this.success = false;
22872 this.fireEvent('drop', dd, e, data);
22873 return this.success;
22877 * Ext JS Library 1.1.1
22878 * Copyright(c) 2006-2007, Ext JS, LLC.
22880 * Originally Released Under LGPL - original licence link has changed is not relivant.
22883 * <script type="text/javascript">
22888 * @class Roo.dd.DragZone
22889 * @extends Roo.dd.DragSource
22890 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22891 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22893 * @param {String/HTMLElement/Element} el The container element
22894 * @param {Object} config
22896 Roo.dd.DragZone = function(el, config){
22897 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22898 if(this.containerScroll){
22899 Roo.dd.ScrollManager.register(this.el);
22903 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22905 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22906 * for auto scrolling during drag operations.
22909 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22910 * method after a failed drop (defaults to "c3daf9" - light blue)
22914 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22915 * for a valid target to drag based on the mouse down. Override this method
22916 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22917 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22918 * @param {EventObject} e The mouse down event
22919 * @return {Object} The dragData
22921 getDragData : function(e){
22922 return Roo.dd.Registry.getHandleFromEvent(e);
22926 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22927 * this.dragData.ddel
22928 * @param {Number} x The x position of the click on the dragged object
22929 * @param {Number} y The y position of the click on the dragged object
22930 * @return {Boolean} true to continue the drag, false to cancel
22932 onInitDrag : function(x, y){
22933 this.proxy.update(this.dragData.ddel.cloneNode(true));
22934 this.onStartDrag(x, y);
22939 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22941 afterRepair : function(){
22943 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22945 this.dragging = false;
22949 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22950 * the XY of this.dragData.ddel
22951 * @param {EventObject} e The mouse up event
22952 * @return {Array} The xy location (e.g. [100, 200])
22954 getRepairXY : function(e){
22955 return Roo.Element.fly(this.dragData.ddel).getXY();
22959 * Ext JS Library 1.1.1
22960 * Copyright(c) 2006-2007, Ext JS, LLC.
22962 * Originally Released Under LGPL - original licence link has changed is not relivant.
22965 * <script type="text/javascript">
22968 * @class Roo.dd.DropZone
22969 * @extends Roo.dd.DropTarget
22970 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22971 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22973 * @param {String/HTMLElement/Element} el The container element
22974 * @param {Object} config
22976 Roo.dd.DropZone = function(el, config){
22977 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22980 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22982 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22983 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22984 * provide your own custom lookup.
22985 * @param {Event} e The event
22986 * @return {Object} data The custom data
22988 getTargetFromEvent : function(e){
22989 return Roo.dd.Registry.getTargetFromEvent(e);
22993 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22994 * that it has registered. This method has no default implementation and should be overridden to provide
22995 * node-specific processing if necessary.
22996 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22997 * {@link #getTargetFromEvent} for this node)
22998 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22999 * @param {Event} e The event
23000 * @param {Object} data An object containing arbitrary data supplied by the drag source
23002 onNodeEnter : function(n, dd, e, data){
23007 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23008 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
23009 * overridden to provide the proper feedback.
23010 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23011 * {@link #getTargetFromEvent} for this node)
23012 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23013 * @param {Event} e The event
23014 * @param {Object} data An object containing arbitrary data supplied by the drag source
23015 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23016 * underlying {@link Roo.dd.StatusProxy} can be updated
23018 onNodeOver : function(n, dd, e, data){
23019 return this.dropAllowed;
23023 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23024 * the drop node without dropping. This method has no default implementation and should be overridden to provide
23025 * node-specific processing if necessary.
23026 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23027 * {@link #getTargetFromEvent} for this node)
23028 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23029 * @param {Event} e The event
23030 * @param {Object} data An object containing arbitrary data supplied by the drag source
23032 onNodeOut : function(n, dd, e, data){
23037 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23038 * the drop node. The default implementation returns false, so it should be overridden to provide the
23039 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23040 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23041 * {@link #getTargetFromEvent} for this node)
23042 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23043 * @param {Event} e The event
23044 * @param {Object} data An object containing arbitrary data supplied by the drag source
23045 * @return {Boolean} True if the drop was valid, else false
23047 onNodeDrop : function(n, dd, e, data){
23052 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23053 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
23054 * it should be overridden to provide the proper feedback if necessary.
23055 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23056 * @param {Event} e The event
23057 * @param {Object} data An object containing arbitrary data supplied by the drag source
23058 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23059 * underlying {@link Roo.dd.StatusProxy} can be updated
23061 onContainerOver : function(dd, e, data){
23062 return this.dropNotAllowed;
23066 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23067 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
23068 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23069 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
23070 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23071 * @param {Event} e The event
23072 * @param {Object} data An object containing arbitrary data supplied by the drag source
23073 * @return {Boolean} True if the drop was valid, else false
23075 onContainerDrop : function(dd, e, data){
23080 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23081 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
23082 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23083 * you should override this method and provide a custom implementation.
23084 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23085 * @param {Event} e The event
23086 * @param {Object} data An object containing arbitrary data supplied by the drag source
23087 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23088 * underlying {@link Roo.dd.StatusProxy} can be updated
23090 notifyEnter : function(dd, e, data){
23091 return this.dropNotAllowed;
23095 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23096 * This method will be called on every mouse movement while the drag source is over the drop zone.
23097 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23098 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23099 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23100 * registered node, it will call {@link #onContainerOver}.
23101 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23102 * @param {Event} e The event
23103 * @param {Object} data An object containing arbitrary data supplied by the drag source
23104 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23105 * underlying {@link Roo.dd.StatusProxy} can be updated
23107 notifyOver : function(dd, e, data){
23108 var n = this.getTargetFromEvent(e);
23109 if(!n){ // not over valid drop target
23110 if(this.lastOverNode){
23111 this.onNodeOut(this.lastOverNode, dd, e, data);
23112 this.lastOverNode = null;
23114 return this.onContainerOver(dd, e, data);
23116 if(this.lastOverNode != n){
23117 if(this.lastOverNode){
23118 this.onNodeOut(this.lastOverNode, dd, e, data);
23120 this.onNodeEnter(n, dd, e, data);
23121 this.lastOverNode = n;
23123 return this.onNodeOver(n, dd, e, data);
23127 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23128 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23129 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23130 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23131 * @param {Event} e The event
23132 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23134 notifyOut : function(dd, e, data){
23135 if(this.lastOverNode){
23136 this.onNodeOut(this.lastOverNode, dd, e, data);
23137 this.lastOverNode = null;
23142 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23143 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23144 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23145 * otherwise it will call {@link #onContainerDrop}.
23146 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23147 * @param {Event} e The event
23148 * @param {Object} data An object containing arbitrary data supplied by the drag source
23149 * @return {Boolean} True if the drop was valid, else false
23151 notifyDrop : function(dd, e, data){
23152 if(this.lastOverNode){
23153 this.onNodeOut(this.lastOverNode, dd, e, data);
23154 this.lastOverNode = null;
23156 var n = this.getTargetFromEvent(e);
23158 this.onNodeDrop(n, dd, e, data) :
23159 this.onContainerDrop(dd, e, data);
23163 triggerCacheRefresh : function(){
23164 Roo.dd.DDM.refreshCache(this.groups);
23168 * Ext JS Library 1.1.1
23169 * Copyright(c) 2006-2007, Ext JS, LLC.
23171 * Originally Released Under LGPL - original licence link has changed is not relivant.
23174 * <script type="text/javascript">
23179 * @class Roo.data.SortTypes
23181 * Defines the default sorting (casting?) comparison functions used when sorting data.
23183 Roo.data.SortTypes = {
23185 * Default sort that does nothing
23186 * @param {Mixed} s The value being converted
23187 * @return {Mixed} The comparison value
23189 none : function(s){
23194 * The regular expression used to strip tags
23198 stripTagsRE : /<\/?[^>]+>/gi,
23201 * Strips all HTML tags to sort on text only
23202 * @param {Mixed} s The value being converted
23203 * @return {String} The comparison value
23205 asText : function(s){
23206 return String(s).replace(this.stripTagsRE, "");
23210 * Strips all HTML tags to sort on text only - Case insensitive
23211 * @param {Mixed} s The value being converted
23212 * @return {String} The comparison value
23214 asUCText : function(s){
23215 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23219 * Case insensitive string
23220 * @param {Mixed} s The value being converted
23221 * @return {String} The comparison value
23223 asUCString : function(s) {
23224 return String(s).toUpperCase();
23229 * @param {Mixed} s The value being converted
23230 * @return {Number} The comparison value
23232 asDate : function(s) {
23236 if(s instanceof Date){
23237 return s.getTime();
23239 return Date.parse(String(s));
23244 * @param {Mixed} s The value being converted
23245 * @return {Float} The comparison value
23247 asFloat : function(s) {
23248 var val = parseFloat(String(s).replace(/,/g, ""));
23257 * @param {Mixed} s The value being converted
23258 * @return {Number} The comparison value
23260 asInt : function(s) {
23261 var val = parseInt(String(s).replace(/,/g, ""));
23269 * Ext JS Library 1.1.1
23270 * Copyright(c) 2006-2007, Ext JS, LLC.
23272 * Originally Released Under LGPL - original licence link has changed is not relivant.
23275 * <script type="text/javascript">
23279 * @class Roo.data.Record
23280 * Instances of this class encapsulate both record <em>definition</em> information, and record
23281 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
23282 * to access Records cached in an {@link Roo.data.Store} object.<br>
23284 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
23285 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
23288 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
23290 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
23291 * {@link #create}. The parameters are the same.
23292 * @param {Array} data An associative Array of data values keyed by the field name.
23293 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
23294 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
23295 * not specified an integer id is generated.
23297 Roo.data.Record = function(data, id){
23298 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
23303 * Generate a constructor for a specific record layout.
23304 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
23305 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
23306 * Each field definition object may contain the following properties: <ul>
23307 * <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,
23308 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
23309 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
23310 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
23311 * is being used, then this is a string containing the javascript expression to reference the data relative to
23312 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
23313 * to the data item relative to the record element. If the mapping expression is the same as the field name,
23314 * this may be omitted.</p></li>
23315 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
23316 * <ul><li>auto (Default, implies no conversion)</li>
23321 * <li>date</li></ul></p></li>
23322 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
23323 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
23324 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
23325 * by the Reader into an object that will be stored in the Record. It is passed the
23326 * following parameters:<ul>
23327 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
23329 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
23331 * <br>usage:<br><pre><code>
23332 var TopicRecord = Roo.data.Record.create(
23333 {name: 'title', mapping: 'topic_title'},
23334 {name: 'author', mapping: 'username'},
23335 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
23336 {name: 'lastPost', mapping: 'post_time', type: 'date'},
23337 {name: 'lastPoster', mapping: 'user2'},
23338 {name: 'excerpt', mapping: 'post_text'}
23341 var myNewRecord = new TopicRecord({
23342 title: 'Do my job please',
23345 lastPost: new Date(),
23346 lastPoster: 'Animal',
23347 excerpt: 'No way dude!'
23349 myStore.add(myNewRecord);
23354 Roo.data.Record.create = function(o){
23355 var f = function(){
23356 f.superclass.constructor.apply(this, arguments);
23358 Roo.extend(f, Roo.data.Record);
23359 var p = f.prototype;
23360 p.fields = new Roo.util.MixedCollection(false, function(field){
23363 for(var i = 0, len = o.length; i < len; i++){
23364 p.fields.add(new Roo.data.Field(o[i]));
23366 f.getField = function(name){
23367 return p.fields.get(name);
23372 Roo.data.Record.AUTO_ID = 1000;
23373 Roo.data.Record.EDIT = 'edit';
23374 Roo.data.Record.REJECT = 'reject';
23375 Roo.data.Record.COMMIT = 'commit';
23377 Roo.data.Record.prototype = {
23379 * Readonly flag - true if this record has been modified.
23388 join : function(store){
23389 this.store = store;
23393 * Set the named field to the specified value.
23394 * @param {String} name The name of the field to set.
23395 * @param {Object} value The value to set the field to.
23397 set : function(name, value){
23398 if(this.data[name] == value){
23402 if(!this.modified){
23403 this.modified = {};
23405 if(typeof this.modified[name] == 'undefined'){
23406 this.modified[name] = this.data[name];
23408 this.data[name] = value;
23409 if(!this.editing && this.store){
23410 this.store.afterEdit(this);
23415 * Get the value of the named field.
23416 * @param {String} name The name of the field to get the value of.
23417 * @return {Object} The value of the field.
23419 get : function(name){
23420 return this.data[name];
23424 beginEdit : function(){
23425 this.editing = true;
23426 this.modified = {};
23430 cancelEdit : function(){
23431 this.editing = false;
23432 delete this.modified;
23436 endEdit : function(){
23437 this.editing = false;
23438 if(this.dirty && this.store){
23439 this.store.afterEdit(this);
23444 * Usually called by the {@link Roo.data.Store} which owns the Record.
23445 * Rejects all changes made to the Record since either creation, or the last commit operation.
23446 * Modified fields are reverted to their original values.
23448 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23449 * of reject operations.
23451 reject : function(){
23452 var m = this.modified;
23454 if(typeof m[n] != "function"){
23455 this.data[n] = m[n];
23458 this.dirty = false;
23459 delete this.modified;
23460 this.editing = false;
23462 this.store.afterReject(this);
23467 * Usually called by the {@link Roo.data.Store} which owns the Record.
23468 * Commits all changes made to the Record since either creation, or the last commit operation.
23470 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23471 * of commit operations.
23473 commit : function(){
23474 this.dirty = false;
23475 delete this.modified;
23476 this.editing = false;
23478 this.store.afterCommit(this);
23483 hasError : function(){
23484 return this.error != null;
23488 clearError : function(){
23493 * Creates a copy of this record.
23494 * @param {String} id (optional) A new record id if you don't want to use this record's id
23497 copy : function(newId) {
23498 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
23502 * Ext JS Library 1.1.1
23503 * Copyright(c) 2006-2007, Ext JS, LLC.
23505 * Originally Released Under LGPL - original licence link has changed is not relivant.
23508 * <script type="text/javascript">
23514 * @class Roo.data.Store
23515 * @extends Roo.util.Observable
23516 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
23517 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
23519 * 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
23520 * has no knowledge of the format of the data returned by the Proxy.<br>
23522 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
23523 * instances from the data object. These records are cached and made available through accessor functions.
23525 * Creates a new Store.
23526 * @param {Object} config A config object containing the objects needed for the Store to access data,
23527 * and read the data into Records.
23529 Roo.data.Store = function(config){
23530 this.data = new Roo.util.MixedCollection(false);
23531 this.data.getKey = function(o){
23534 this.baseParams = {};
23536 this.paramNames = {
23541 "multisort" : "_multisort"
23544 if(config && config.data){
23545 this.inlineData = config.data;
23546 delete config.data;
23549 Roo.apply(this, config);
23551 if(this.reader){ // reader passed
23552 this.reader = Roo.factory(this.reader, Roo.data);
23553 this.reader.xmodule = this.xmodule || false;
23554 if(!this.recordType){
23555 this.recordType = this.reader.recordType;
23557 if(this.reader.onMetaChange){
23558 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
23562 if(this.recordType){
23563 this.fields = this.recordType.prototype.fields;
23565 this.modified = [];
23569 * @event datachanged
23570 * Fires when the data cache has changed, and a widget which is using this Store
23571 * as a Record cache should refresh its view.
23572 * @param {Store} this
23574 datachanged : true,
23576 * @event metachange
23577 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
23578 * @param {Store} this
23579 * @param {Object} meta The JSON metadata
23584 * Fires when Records have been added to the Store
23585 * @param {Store} this
23586 * @param {Roo.data.Record[]} records The array of Records added
23587 * @param {Number} index The index at which the record(s) were added
23592 * Fires when a Record has been removed from the Store
23593 * @param {Store} this
23594 * @param {Roo.data.Record} record The Record that was removed
23595 * @param {Number} index The index at which the record was removed
23600 * Fires when a Record has been updated
23601 * @param {Store} this
23602 * @param {Roo.data.Record} record The Record that was updated
23603 * @param {String} operation The update operation being performed. Value may be one of:
23605 Roo.data.Record.EDIT
23606 Roo.data.Record.REJECT
23607 Roo.data.Record.COMMIT
23613 * Fires when the data cache has been cleared.
23614 * @param {Store} this
23618 * @event beforeload
23619 * Fires before a request is made for a new data object. If the beforeload handler returns false
23620 * the load action will be canceled.
23621 * @param {Store} this
23622 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23626 * @event beforeloadadd
23627 * Fires after a new set of Records has been loaded.
23628 * @param {Store} this
23629 * @param {Roo.data.Record[]} records The Records that were loaded
23630 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23632 beforeloadadd : true,
23635 * Fires after a new set of Records has been loaded, before they are added to the store.
23636 * @param {Store} this
23637 * @param {Roo.data.Record[]} records The Records that were loaded
23638 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23639 * @params {Object} return from reader
23643 * @event loadexception
23644 * Fires if an exception occurs in the Proxy during loading.
23645 * Called with the signature of the Proxy's "loadexception" event.
23646 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
23649 * @param {Object} return from JsonData.reader() - success, totalRecords, records
23650 * @param {Object} load options
23651 * @param {Object} jsonData from your request (normally this contains the Exception)
23653 loadexception : true
23657 this.proxy = Roo.factory(this.proxy, Roo.data);
23658 this.proxy.xmodule = this.xmodule || false;
23659 this.relayEvents(this.proxy, ["loadexception"]);
23661 this.sortToggle = {};
23662 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
23664 Roo.data.Store.superclass.constructor.call(this);
23666 if(this.inlineData){
23667 this.loadData(this.inlineData);
23668 delete this.inlineData;
23672 Roo.extend(Roo.data.Store, Roo.util.Observable, {
23674 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
23675 * without a remote query - used by combo/forms at present.
23679 * @cfg {Roo.data.DataProxy} proxy [required] The Proxy object which provides access to a data object.
23682 * @cfg {Array} data Inline data to be loaded when the store is initialized.
23685 * @cfg {Roo.data.DataReader} reader [required] The Reader object which processes the data object and returns
23686 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
23689 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
23690 * on any HTTP request
23693 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
23696 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
23700 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
23701 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
23703 remoteSort : false,
23706 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
23707 * loaded or when a record is removed. (defaults to false).
23709 pruneModifiedRecords : false,
23712 lastOptions : null,
23715 * Add Records to the Store and fires the add event.
23716 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23718 add : function(records){
23719 records = [].concat(records);
23720 for(var i = 0, len = records.length; i < len; i++){
23721 records[i].join(this);
23723 var index = this.data.length;
23724 this.data.addAll(records);
23725 this.fireEvent("add", this, records, index);
23729 * Remove a Record from the Store and fires the remove event.
23730 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23732 remove : function(record){
23733 var index = this.data.indexOf(record);
23734 this.data.removeAt(index);
23736 if(this.pruneModifiedRecords){
23737 this.modified.remove(record);
23739 this.fireEvent("remove", this, record, index);
23743 * Remove all Records from the Store and fires the clear event.
23745 removeAll : function(){
23747 if(this.pruneModifiedRecords){
23748 this.modified = [];
23750 this.fireEvent("clear", this);
23754 * Inserts Records to the Store at the given index and fires the add event.
23755 * @param {Number} index The start index at which to insert the passed Records.
23756 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23758 insert : function(index, records){
23759 records = [].concat(records);
23760 for(var i = 0, len = records.length; i < len; i++){
23761 this.data.insert(index, records[i]);
23762 records[i].join(this);
23764 this.fireEvent("add", this, records, index);
23768 * Get the index within the cache of the passed Record.
23769 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23770 * @return {Number} The index of the passed Record. Returns -1 if not found.
23772 indexOf : function(record){
23773 return this.data.indexOf(record);
23777 * Get the index within the cache of the Record with the passed id.
23778 * @param {String} id The id of the Record to find.
23779 * @return {Number} The index of the Record. Returns -1 if not found.
23781 indexOfId : function(id){
23782 return this.data.indexOfKey(id);
23786 * Get the Record with the specified id.
23787 * @param {String} id The id of the Record to find.
23788 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23790 getById : function(id){
23791 return this.data.key(id);
23795 * Get the Record at the specified index.
23796 * @param {Number} index The index of the Record to find.
23797 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23799 getAt : function(index){
23800 return this.data.itemAt(index);
23804 * Returns a range of Records between specified indices.
23805 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23806 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23807 * @return {Roo.data.Record[]} An array of Records
23809 getRange : function(start, end){
23810 return this.data.getRange(start, end);
23814 storeOptions : function(o){
23815 o = Roo.apply({}, o);
23818 this.lastOptions = o;
23822 * Loads the Record cache from the configured Proxy using the configured Reader.
23824 * If using remote paging, then the first load call must specify the <em>start</em>
23825 * and <em>limit</em> properties in the options.params property to establish the initial
23826 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23828 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23829 * and this call will return before the new data has been loaded. Perform any post-processing
23830 * in a callback function, or in a "load" event handler.</strong>
23832 * @param {Object} options An object containing properties which control loading options:<ul>
23833 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23834 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23835 * passed the following arguments:<ul>
23836 * <li>r : Roo.data.Record[]</li>
23837 * <li>options: Options object from the load call</li>
23838 * <li>success: Boolean success indicator</li></ul></li>
23839 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23840 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23843 load : function(options){
23844 options = options || {};
23845 if(this.fireEvent("beforeload", this, options) !== false){
23846 this.storeOptions(options);
23847 var p = Roo.apply(options.params || {}, this.baseParams);
23848 // if meta was not loaded from remote source.. try requesting it.
23849 if (!this.reader.metaFromRemote) {
23850 p._requestMeta = 1;
23852 if(this.sortInfo && this.remoteSort){
23853 var pn = this.paramNames;
23854 p[pn["sort"]] = this.sortInfo.field;
23855 p[pn["dir"]] = this.sortInfo.direction;
23857 if (this.multiSort) {
23858 var pn = this.paramNames;
23859 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23862 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23867 * Reloads the Record cache from the configured Proxy using the configured Reader and
23868 * the options from the last load operation performed.
23869 * @param {Object} options (optional) An object containing properties which may override the options
23870 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23871 * the most recently used options are reused).
23873 reload : function(options){
23874 this.load(Roo.applyIf(options||{}, this.lastOptions));
23878 // Called as a callback by the Reader during a load operation.
23879 loadRecords : function(o, options, success){
23880 if(!o || success === false){
23881 if(success !== false){
23882 this.fireEvent("load", this, [], options, o);
23884 if(options.callback){
23885 options.callback.call(options.scope || this, [], options, false);
23889 // if data returned failure - throw an exception.
23890 if (o.success === false) {
23891 // show a message if no listener is registered.
23892 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23893 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23895 // loadmask wil be hooked into this..
23896 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23899 var r = o.records, t = o.totalRecords || r.length;
23901 this.fireEvent("beforeloadadd", this, r, options, o);
23903 if(!options || options.add !== true){
23904 if(this.pruneModifiedRecords){
23905 this.modified = [];
23907 for(var i = 0, len = r.length; i < len; i++){
23911 this.data = this.snapshot;
23912 delete this.snapshot;
23915 this.data.addAll(r);
23916 this.totalLength = t;
23918 this.fireEvent("datachanged", this);
23920 this.totalLength = Math.max(t, this.data.length+r.length);
23924 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23926 var e = new Roo.data.Record({});
23928 e.set(this.parent.displayField, this.parent.emptyTitle);
23929 e.set(this.parent.valueField, '');
23934 this.fireEvent("load", this, r, options, o);
23935 if(options.callback){
23936 options.callback.call(options.scope || this, r, options, true);
23942 * Loads data from a passed data block. A Reader which understands the format of the data
23943 * must have been configured in the constructor.
23944 * @param {Object} data The data block from which to read the Records. The format of the data expected
23945 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23946 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23948 loadData : function(o, append){
23949 var r = this.reader.readRecords(o);
23950 this.loadRecords(r, {add: append}, true);
23954 * using 'cn' the nested child reader read the child array into it's child stores.
23955 * @param {Object} rec The record with a 'children array
23957 loadDataFromChildren : function(rec)
23959 this.loadData(this.reader.toLoadData(rec));
23964 * Gets the number of cached records.
23966 * <em>If using paging, this may not be the total size of the dataset. If the data object
23967 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23968 * the data set size</em>
23970 getCount : function(){
23971 return this.data.length || 0;
23975 * Gets the total number of records in the dataset as returned by the server.
23977 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23978 * the dataset size</em>
23980 getTotalCount : function(){
23981 return this.totalLength || 0;
23985 * Returns the sort state of the Store as an object with two properties:
23987 field {String} The name of the field by which the Records are sorted
23988 direction {String} The sort order, "ASC" or "DESC"
23991 getSortState : function(){
23992 return this.sortInfo;
23996 applySort : function(){
23997 if(this.sortInfo && !this.remoteSort){
23998 var s = this.sortInfo, f = s.field;
23999 var st = this.fields.get(f).sortType;
24000 var fn = function(r1, r2){
24001 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
24002 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
24004 this.data.sort(s.direction, fn);
24005 if(this.snapshot && this.snapshot != this.data){
24006 this.snapshot.sort(s.direction, fn);
24012 * Sets the default sort column and order to be used by the next load operation.
24013 * @param {String} fieldName The name of the field to sort by.
24014 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24016 setDefaultSort : function(field, dir){
24017 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
24021 * Sort the Records.
24022 * If remote sorting is used, the sort is performed on the server, and the cache is
24023 * reloaded. If local sorting is used, the cache is sorted internally.
24024 * @param {String} fieldName The name of the field to sort by.
24025 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24027 sort : function(fieldName, dir){
24028 var f = this.fields.get(fieldName);
24030 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
24032 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
24033 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
24038 this.sortToggle[f.name] = dir;
24039 this.sortInfo = {field: f.name, direction: dir};
24040 if(!this.remoteSort){
24042 this.fireEvent("datachanged", this);
24044 this.load(this.lastOptions);
24049 * Calls the specified function for each of the Records in the cache.
24050 * @param {Function} fn The function to call. The Record is passed as the first parameter.
24051 * Returning <em>false</em> aborts and exits the iteration.
24052 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
24054 each : function(fn, scope){
24055 this.data.each(fn, scope);
24059 * Gets all records modified since the last commit. Modified records are persisted across load operations
24060 * (e.g., during paging).
24061 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
24063 getModifiedRecords : function(){
24064 return this.modified;
24068 createFilterFn : function(property, value, anyMatch){
24069 if(!value.exec){ // not a regex
24070 value = String(value);
24071 if(value.length == 0){
24074 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
24076 return function(r){
24077 return value.test(r.data[property]);
24082 * Sums the value of <i>property</i> for each record between start and end and returns the result.
24083 * @param {String} property A field on your records
24084 * @param {Number} start The record index to start at (defaults to 0)
24085 * @param {Number} end The last record index to include (defaults to length - 1)
24086 * @return {Number} The sum
24088 sum : function(property, start, end){
24089 var rs = this.data.items, v = 0;
24090 start = start || 0;
24091 end = (end || end === 0) ? end : rs.length-1;
24093 for(var i = start; i <= end; i++){
24094 v += (rs[i].data[property] || 0);
24100 * Filter the records by a specified property.
24101 * @param {String} field A field on your records
24102 * @param {String/RegExp} value Either a string that the field
24103 * should start with or a RegExp to test against the field
24104 * @param {Boolean} anyMatch True to match any part not just the beginning
24106 filter : function(property, value, anyMatch){
24107 var fn = this.createFilterFn(property, value, anyMatch);
24108 return fn ? this.filterBy(fn) : this.clearFilter();
24112 * Filter by a function. The specified function will be called with each
24113 * record in this data source. If the function returns true the record is included,
24114 * otherwise it is filtered.
24115 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24116 * @param {Object} scope (optional) The scope of the function (defaults to this)
24118 filterBy : function(fn, scope){
24119 this.snapshot = this.snapshot || this.data;
24120 this.data = this.queryBy(fn, scope||this);
24121 this.fireEvent("datachanged", this);
24125 * Query the records by a specified property.
24126 * @param {String} field A field on your records
24127 * @param {String/RegExp} value Either a string that the field
24128 * should start with or a RegExp to test against the field
24129 * @param {Boolean} anyMatch True to match any part not just the beginning
24130 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24132 query : function(property, value, anyMatch){
24133 var fn = this.createFilterFn(property, value, anyMatch);
24134 return fn ? this.queryBy(fn) : this.data.clone();
24138 * Query by a function. The specified function will be called with each
24139 * record in this data source. If the function returns true the record is included
24141 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24142 * @param {Object} scope (optional) The scope of the function (defaults to this)
24143 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24145 queryBy : function(fn, scope){
24146 var data = this.snapshot || this.data;
24147 return data.filterBy(fn, scope||this);
24151 * Collects unique values for a particular dataIndex from this store.
24152 * @param {String} dataIndex The property to collect
24153 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24154 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24155 * @return {Array} An array of the unique values
24157 collect : function(dataIndex, allowNull, bypassFilter){
24158 var d = (bypassFilter === true && this.snapshot) ?
24159 this.snapshot.items : this.data.items;
24160 var v, sv, r = [], l = {};
24161 for(var i = 0, len = d.length; i < len; i++){
24162 v = d[i].data[dataIndex];
24164 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24173 * Revert to a view of the Record cache with no filtering applied.
24174 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24176 clearFilter : function(suppressEvent){
24177 if(this.snapshot && this.snapshot != this.data){
24178 this.data = this.snapshot;
24179 delete this.snapshot;
24180 if(suppressEvent !== true){
24181 this.fireEvent("datachanged", this);
24187 afterEdit : function(record){
24188 if(this.modified.indexOf(record) == -1){
24189 this.modified.push(record);
24191 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24195 afterReject : function(record){
24196 this.modified.remove(record);
24197 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24201 afterCommit : function(record){
24202 this.modified.remove(record);
24203 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24207 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24208 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24210 commitChanges : function(){
24211 var m = this.modified.slice(0);
24212 this.modified = [];
24213 for(var i = 0, len = m.length; i < len; i++){
24219 * Cancel outstanding changes on all changed records.
24221 rejectChanges : function(){
24222 var m = this.modified.slice(0);
24223 this.modified = [];
24224 for(var i = 0, len = m.length; i < len; i++){
24229 onMetaChange : function(meta, rtype, o){
24230 this.recordType = rtype;
24231 this.fields = rtype.prototype.fields;
24232 delete this.snapshot;
24233 this.sortInfo = meta.sortInfo || this.sortInfo;
24234 this.modified = [];
24235 this.fireEvent('metachange', this, this.reader.meta);
24238 moveIndex : function(data, type)
24240 var index = this.indexOf(data);
24242 var newIndex = index + type;
24246 this.insert(newIndex, data);
24251 * Ext JS Library 1.1.1
24252 * Copyright(c) 2006-2007, Ext JS, LLC.
24254 * Originally Released Under LGPL - original licence link has changed is not relivant.
24257 * <script type="text/javascript">
24261 * @class Roo.data.SimpleStore
24262 * @extends Roo.data.Store
24263 * Small helper class to make creating Stores from Array data easier.
24264 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24265 * @cfg {Array} fields An array of field definition objects, or field name strings.
24266 * @cfg {Object} an existing reader (eg. copied from another store)
24267 * @cfg {Array} data The multi-dimensional array of data
24268 * @cfg {Roo.data.DataProxy} proxy [not-required]
24269 * @cfg {Roo.data.Reader} reader [not-required]
24271 * @param {Object} config
24273 Roo.data.SimpleStore = function(config)
24275 Roo.data.SimpleStore.superclass.constructor.call(this, {
24277 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24280 Roo.data.Record.create(config.fields)
24282 proxy : new Roo.data.MemoryProxy(config.data)
24286 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24288 * Ext JS Library 1.1.1
24289 * Copyright(c) 2006-2007, Ext JS, LLC.
24291 * Originally Released Under LGPL - original licence link has changed is not relivant.
24294 * <script type="text/javascript">
24299 * @extends Roo.data.Store
24300 * @class Roo.data.JsonStore
24301 * Small helper class to make creating Stores for JSON data easier. <br/>
24303 var store = new Roo.data.JsonStore({
24304 url: 'get-images.php',
24306 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24309 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24310 * JsonReader and HttpProxy (unless inline data is provided).</b>
24311 * @cfg {Array} fields An array of field definition objects, or field name strings.
24313 * @param {Object} config
24315 Roo.data.JsonStore = function(c){
24316 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24317 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24318 reader: new Roo.data.JsonReader(c, c.fields)
24321 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
24323 * Ext JS Library 1.1.1
24324 * Copyright(c) 2006-2007, Ext JS, LLC.
24326 * Originally Released Under LGPL - original licence link has changed is not relivant.
24329 * <script type="text/javascript">
24333 Roo.data.Field = function(config){
24334 if(typeof config == "string"){
24335 config = {name: config};
24337 Roo.apply(this, config);
24340 this.type = "auto";
24343 var st = Roo.data.SortTypes;
24344 // named sortTypes are supported, here we look them up
24345 if(typeof this.sortType == "string"){
24346 this.sortType = st[this.sortType];
24349 // set default sortType for strings and dates
24350 if(!this.sortType){
24353 this.sortType = st.asUCString;
24356 this.sortType = st.asDate;
24359 this.sortType = st.none;
24364 var stripRe = /[\$,%]/g;
24366 // prebuilt conversion function for this field, instead of
24367 // switching every time we're reading a value
24369 var cv, dateFormat = this.dateFormat;
24374 cv = function(v){ return v; };
24377 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24381 return v !== undefined && v !== null && v !== '' ?
24382 parseInt(String(v).replace(stripRe, ""), 10) : '';
24387 return v !== undefined && v !== null && v !== '' ?
24388 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24393 cv = function(v){ return v === true || v === "true" || v == 1; };
24400 if(v instanceof Date){
24404 if(dateFormat == "timestamp"){
24405 return new Date(v*1000);
24407 return Date.parseDate(v, dateFormat);
24409 var parsed = Date.parse(v);
24410 return parsed ? new Date(parsed) : null;
24419 Roo.data.Field.prototype = {
24427 * Ext JS Library 1.1.1
24428 * Copyright(c) 2006-2007, Ext JS, LLC.
24430 * Originally Released Under LGPL - original licence link has changed is not relivant.
24433 * <script type="text/javascript">
24436 // Base class for reading structured data from a data source. This class is intended to be
24437 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24440 * @class Roo.data.DataReader
24442 * Base class for reading structured data from a data source. This class is intended to be
24443 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24446 Roo.data.DataReader = function(meta, recordType){
24450 this.recordType = recordType instanceof Array ?
24451 Roo.data.Record.create(recordType) : recordType;
24454 Roo.data.DataReader.prototype = {
24457 readerType : 'Data',
24459 * Create an empty record
24460 * @param {Object} data (optional) - overlay some values
24461 * @return {Roo.data.Record} record created.
24463 newRow : function(d) {
24465 this.recordType.prototype.fields.each(function(c) {
24467 case 'int' : da[c.name] = 0; break;
24468 case 'date' : da[c.name] = new Date(); break;
24469 case 'float' : da[c.name] = 0.0; break;
24470 case 'boolean' : da[c.name] = false; break;
24471 default : da[c.name] = ""; break;
24475 return new this.recordType(Roo.apply(da, d));
24481 * Ext JS Library 1.1.1
24482 * Copyright(c) 2006-2007, Ext JS, LLC.
24484 * Originally Released Under LGPL - original licence link has changed is not relivant.
24487 * <script type="text/javascript">
24491 * @class Roo.data.DataProxy
24492 * @extends Roo.util.Observable
24494 * This class is an abstract base class for implementations which provide retrieval of
24495 * unformatted data objects.<br>
24497 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24498 * (of the appropriate type which knows how to parse the data object) to provide a block of
24499 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24501 * Custom implementations must implement the load method as described in
24502 * {@link Roo.data.HttpProxy#load}.
24504 Roo.data.DataProxy = function(){
24507 * @event beforeload
24508 * Fires before a network request is made to retrieve a data object.
24509 * @param {Object} This DataProxy object.
24510 * @param {Object} params The params parameter to the load function.
24515 * Fires before the load method's callback is called.
24516 * @param {Object} This DataProxy object.
24517 * @param {Object} o The data object.
24518 * @param {Object} arg The callback argument object passed to the load function.
24522 * @event loadexception
24523 * Fires if an Exception occurs during data retrieval.
24524 * @param {Object} This DataProxy object.
24525 * @param {Object} o The data object.
24526 * @param {Object} arg The callback argument object passed to the load function.
24527 * @param {Object} e The Exception.
24529 loadexception : true
24531 Roo.data.DataProxy.superclass.constructor.call(this);
24534 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24537 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24541 * Ext JS Library 1.1.1
24542 * Copyright(c) 2006-2007, Ext JS, LLC.
24544 * Originally Released Under LGPL - original licence link has changed is not relivant.
24547 * <script type="text/javascript">
24550 * @class Roo.data.MemoryProxy
24551 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24552 * to the Reader when its load method is called.
24554 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24556 Roo.data.MemoryProxy = function(data){
24560 Roo.data.MemoryProxy.superclass.constructor.call(this);
24564 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24567 * Load data from the requested source (in this case an in-memory
24568 * data object passed to the constructor), read the data object into
24569 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24570 * process that block using the passed callback.
24571 * @param {Object} params This parameter is not used by the MemoryProxy class.
24572 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24573 * object into a block of Roo.data.Records.
24574 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24575 * The function must be passed <ul>
24576 * <li>The Record block object</li>
24577 * <li>The "arg" argument from the load function</li>
24578 * <li>A boolean success indicator</li>
24580 * @param {Object} scope The scope in which to call the callback
24581 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24583 load : function(params, reader, callback, scope, arg){
24584 params = params || {};
24587 result = reader.readRecords(params.data ? params.data :this.data);
24589 this.fireEvent("loadexception", this, arg, null, e);
24590 callback.call(scope, null, arg, false);
24593 callback.call(scope, result, arg, true);
24597 update : function(params, records){
24602 * Ext JS Library 1.1.1
24603 * Copyright(c) 2006-2007, Ext JS, LLC.
24605 * Originally Released Under LGPL - original licence link has changed is not relivant.
24608 * <script type="text/javascript">
24611 * @class Roo.data.HttpProxy
24612 * @extends Roo.data.DataProxy
24613 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24614 * configured to reference a certain URL.<br><br>
24616 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24617 * from which the running page was served.<br><br>
24619 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24621 * Be aware that to enable the browser to parse an XML document, the server must set
24622 * the Content-Type header in the HTTP response to "text/xml".
24624 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24625 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24626 * will be used to make the request.
24628 Roo.data.HttpProxy = function(conn){
24629 Roo.data.HttpProxy.superclass.constructor.call(this);
24630 // is conn a conn config or a real conn?
24632 this.useAjax = !conn || !conn.events;
24636 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24637 // thse are take from connection...
24640 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24643 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24644 * extra parameters to each request made by this object. (defaults to undefined)
24647 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24648 * to each request made by this object. (defaults to undefined)
24651 * @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)
24654 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24657 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24663 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24667 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24668 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24669 * a finer-grained basis than the DataProxy events.
24671 getConnection : function(){
24672 return this.useAjax ? Roo.Ajax : this.conn;
24676 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24677 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24678 * process that block using the passed callback.
24679 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24680 * for the request to the remote server.
24681 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24682 * object into a block of Roo.data.Records.
24683 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24684 * The function must be passed <ul>
24685 * <li>The Record block object</li>
24686 * <li>The "arg" argument from the load function</li>
24687 * <li>A boolean success indicator</li>
24689 * @param {Object} scope The scope in which to call the callback
24690 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24692 load : function(params, reader, callback, scope, arg){
24693 if(this.fireEvent("beforeload", this, params) !== false){
24695 params : params || {},
24697 callback : callback,
24702 callback : this.loadResponse,
24706 Roo.applyIf(o, this.conn);
24707 if(this.activeRequest){
24708 Roo.Ajax.abort(this.activeRequest);
24710 this.activeRequest = Roo.Ajax.request(o);
24712 this.conn.request(o);
24715 callback.call(scope||this, null, arg, false);
24720 loadResponse : function(o, success, response){
24721 delete this.activeRequest;
24723 this.fireEvent("loadexception", this, o, response);
24724 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24729 result = o.reader.read(response);
24731 this.fireEvent("loadexception", this, o, response, e);
24732 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24736 this.fireEvent("load", this, o, o.request.arg);
24737 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24741 update : function(dataSet){
24746 updateResponse : function(dataSet){
24751 * Ext JS Library 1.1.1
24752 * Copyright(c) 2006-2007, Ext JS, LLC.
24754 * Originally Released Under LGPL - original licence link has changed is not relivant.
24757 * <script type="text/javascript">
24761 * @class Roo.data.ScriptTagProxy
24762 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24763 * other than the originating domain of the running page.<br><br>
24765 * <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
24766 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24768 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24769 * source code that is used as the source inside a <script> tag.<br><br>
24771 * In order for the browser to process the returned data, the server must wrap the data object
24772 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24773 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24774 * depending on whether the callback name was passed:
24777 boolean scriptTag = false;
24778 String cb = request.getParameter("callback");
24781 response.setContentType("text/javascript");
24783 response.setContentType("application/x-json");
24785 Writer out = response.getWriter();
24787 out.write(cb + "(");
24789 out.print(dataBlock.toJsonString());
24796 * @param {Object} config A configuration object.
24798 Roo.data.ScriptTagProxy = function(config){
24799 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24800 Roo.apply(this, config);
24801 this.head = document.getElementsByTagName("head")[0];
24804 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24806 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24808 * @cfg {String} url The URL from which to request the data object.
24811 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24815 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24816 * the server the name of the callback function set up by the load call to process the returned data object.
24817 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24818 * javascript output which calls this named function passing the data object as its only parameter.
24820 callbackParam : "callback",
24822 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24823 * name to the request.
24828 * Load data from the configured URL, read the data object into
24829 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24830 * process that block using the passed callback.
24831 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24832 * for the request to the remote server.
24833 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24834 * object into a block of Roo.data.Records.
24835 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24836 * The function must be passed <ul>
24837 * <li>The Record block object</li>
24838 * <li>The "arg" argument from the load function</li>
24839 * <li>A boolean success indicator</li>
24841 * @param {Object} scope The scope in which to call the callback
24842 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24844 load : function(params, reader, callback, scope, arg){
24845 if(this.fireEvent("beforeload", this, params) !== false){
24847 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24849 var url = this.url;
24850 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24852 url += "&_dc=" + (new Date().getTime());
24854 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24857 cb : "stcCallback"+transId,
24858 scriptId : "stcScript"+transId,
24862 callback : callback,
24868 window[trans.cb] = function(o){
24869 conn.handleResponse(o, trans);
24872 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24874 if(this.autoAbort !== false){
24878 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24880 var script = document.createElement("script");
24881 script.setAttribute("src", url);
24882 script.setAttribute("type", "text/javascript");
24883 script.setAttribute("id", trans.scriptId);
24884 this.head.appendChild(script);
24886 this.trans = trans;
24888 callback.call(scope||this, null, arg, false);
24893 isLoading : function(){
24894 return this.trans ? true : false;
24898 * Abort the current server request.
24900 abort : function(){
24901 if(this.isLoading()){
24902 this.destroyTrans(this.trans);
24907 destroyTrans : function(trans, isLoaded){
24908 this.head.removeChild(document.getElementById(trans.scriptId));
24909 clearTimeout(trans.timeoutId);
24911 window[trans.cb] = undefined;
24913 delete window[trans.cb];
24916 // if hasn't been loaded, wait for load to remove it to prevent script error
24917 window[trans.cb] = function(){
24918 window[trans.cb] = undefined;
24920 delete window[trans.cb];
24927 handleResponse : function(o, trans){
24928 this.trans = false;
24929 this.destroyTrans(trans, true);
24932 result = trans.reader.readRecords(o);
24934 this.fireEvent("loadexception", this, o, trans.arg, e);
24935 trans.callback.call(trans.scope||window, null, trans.arg, false);
24938 this.fireEvent("load", this, o, trans.arg);
24939 trans.callback.call(trans.scope||window, result, trans.arg, true);
24943 handleFailure : function(trans){
24944 this.trans = false;
24945 this.destroyTrans(trans, false);
24946 this.fireEvent("loadexception", this, null, trans.arg);
24947 trans.callback.call(trans.scope||window, null, trans.arg, false);
24951 * Ext JS Library 1.1.1
24952 * Copyright(c) 2006-2007, Ext JS, LLC.
24954 * Originally Released Under LGPL - original licence link has changed is not relivant.
24957 * <script type="text/javascript">
24961 * @class Roo.data.JsonReader
24962 * @extends Roo.data.DataReader
24963 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24964 * based on mappings in a provided Roo.data.Record constructor.
24966 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24967 * in the reply previously.
24972 var RecordDef = Roo.data.Record.create([
24973 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24974 {name: 'occupation'} // This field will use "occupation" as the mapping.
24976 var myReader = new Roo.data.JsonReader({
24977 totalProperty: "results", // The property which contains the total dataset size (optional)
24978 root: "rows", // The property which contains an Array of row objects
24979 id: "id" // The property within each row object that provides an ID for the record (optional)
24983 * This would consume a JSON file like this:
24985 { 'results': 2, 'rows': [
24986 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24987 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24990 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24991 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24992 * paged from the remote server.
24993 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24994 * @cfg {String} root name of the property which contains the Array of row objects.
24995 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24996 * @cfg {Array} fields Array of field definition objects
24998 * Create a new JsonReader
24999 * @param {Object} meta Metadata configuration options
25000 * @param {Object} recordType Either an Array of field definition objects,
25001 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
25003 Roo.data.JsonReader = function(meta, recordType){
25006 // set some defaults:
25007 Roo.applyIf(meta, {
25008 totalProperty: 'total',
25009 successProperty : 'success',
25014 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25016 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
25018 readerType : 'Json',
25021 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
25022 * Used by Store query builder to append _requestMeta to params.
25025 metaFromRemote : false,
25027 * This method is only used by a DataProxy which has retrieved data from a remote server.
25028 * @param {Object} response The XHR object which contains the JSON data in its responseText.
25029 * @return {Object} data A data block which is used by an Roo.data.Store object as
25030 * a cache of Roo.data.Records.
25032 read : function(response){
25033 var json = response.responseText;
25035 var o = /* eval:var:o */ eval("("+json+")");
25037 throw {message: "JsonReader.read: Json object not found"};
25043 this.metaFromRemote = true;
25044 this.meta = o.metaData;
25045 this.recordType = Roo.data.Record.create(o.metaData.fields);
25046 this.onMetaChange(this.meta, this.recordType, o);
25048 return this.readRecords(o);
25051 // private function a store will implement
25052 onMetaChange : function(meta, recordType, o){
25059 simpleAccess: function(obj, subsc) {
25066 getJsonAccessor: function(){
25068 return function(expr) {
25070 return(re.test(expr))
25071 ? new Function("obj", "return obj." + expr)
25076 return Roo.emptyFn;
25081 * Create a data block containing Roo.data.Records from an XML document.
25082 * @param {Object} o An object which contains an Array of row objects in the property specified
25083 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
25084 * which contains the total size of the dataset.
25085 * @return {Object} data A data block which is used by an Roo.data.Store object as
25086 * a cache of Roo.data.Records.
25088 readRecords : function(o){
25090 * After any data loads, the raw JSON data is available for further custom processing.
25094 var s = this.meta, Record = this.recordType,
25095 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
25097 // Generate extraction functions for the totalProperty, the root, the id, and for each field
25099 if(s.totalProperty) {
25100 this.getTotal = this.getJsonAccessor(s.totalProperty);
25102 if(s.successProperty) {
25103 this.getSuccess = this.getJsonAccessor(s.successProperty);
25105 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
25107 var g = this.getJsonAccessor(s.id);
25108 this.getId = function(rec) {
25110 return (r === undefined || r === "") ? null : r;
25113 this.getId = function(){return null;};
25116 for(var jj = 0; jj < fl; jj++){
25118 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
25119 this.ef[jj] = this.getJsonAccessor(map);
25123 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
25124 if(s.totalProperty){
25125 var vt = parseInt(this.getTotal(o), 10);
25130 if(s.successProperty){
25131 var vs = this.getSuccess(o);
25132 if(vs === false || vs === 'false'){
25137 for(var i = 0; i < c; i++){
25140 var id = this.getId(n);
25141 for(var j = 0; j < fl; j++){
25143 var v = this.ef[j](n);
25145 Roo.log('missing convert for ' + f.name);
25149 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25151 var record = new Record(values, id);
25153 records[i] = record;
25159 totalRecords : totalRecords
25162 // used when loading children.. @see loadDataFromChildren
25163 toLoadData: function(rec)
25165 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25166 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25167 return { data : data, total : data.length };
25172 * Ext JS Library 1.1.1
25173 * Copyright(c) 2006-2007, Ext JS, LLC.
25175 * Originally Released Under LGPL - original licence link has changed is not relivant.
25178 * <script type="text/javascript">
25182 * @class Roo.data.XmlReader
25183 * @extends Roo.data.DataReader
25184 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25185 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25187 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25188 * header in the HTTP response must be set to "text/xml".</em>
25192 var RecordDef = Roo.data.Record.create([
25193 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25194 {name: 'occupation'} // This field will use "occupation" as the mapping.
25196 var myReader = new Roo.data.XmlReader({
25197 totalRecords: "results", // The element which contains the total dataset size (optional)
25198 record: "row", // The repeated element which contains row information
25199 id: "id" // The element within the row that provides an ID for the record (optional)
25203 * This would consume an XML file like this:
25207 <results>2</results>
25210 <name>Bill</name>
25211 <occupation>Gardener</occupation>
25215 <name>Ben</name>
25216 <occupation>Horticulturalist</occupation>
25220 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25221 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25222 * paged from the remote server.
25223 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25224 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25225 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25226 * a record identifier value.
25228 * Create a new XmlReader
25229 * @param {Object} meta Metadata configuration options
25230 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25231 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25232 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25234 Roo.data.XmlReader = function(meta, recordType){
25236 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25238 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25240 readerType : 'Xml',
25243 * This method is only used by a DataProxy which has retrieved data from a remote server.
25244 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25245 * to contain a method called 'responseXML' that returns an XML document object.
25246 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25247 * a cache of Roo.data.Records.
25249 read : function(response){
25250 var doc = response.responseXML;
25252 throw {message: "XmlReader.read: XML Document not available"};
25254 return this.readRecords(doc);
25258 * Create a data block containing Roo.data.Records from an XML document.
25259 * @param {Object} doc A parsed XML document.
25260 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25261 * a cache of Roo.data.Records.
25263 readRecords : function(doc){
25265 * After any data loads/reads, the raw XML Document is available for further custom processing.
25266 * @type XMLDocument
25268 this.xmlData = doc;
25269 var root = doc.documentElement || doc;
25270 var q = Roo.DomQuery;
25271 var recordType = this.recordType, fields = recordType.prototype.fields;
25272 var sid = this.meta.id;
25273 var totalRecords = 0, success = true;
25274 if(this.meta.totalRecords){
25275 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25278 if(this.meta.success){
25279 var sv = q.selectValue(this.meta.success, root, true);
25280 success = sv !== false && sv !== 'false';
25283 var ns = q.select(this.meta.record, root);
25284 for(var i = 0, len = ns.length; i < len; i++) {
25287 var id = sid ? q.selectValue(sid, n) : undefined;
25288 for(var j = 0, jlen = fields.length; j < jlen; j++){
25289 var f = fields.items[j];
25290 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25292 values[f.name] = v;
25294 var record = new recordType(values, id);
25296 records[records.length] = record;
25302 totalRecords : totalRecords || records.length
25307 * Ext JS Library 1.1.1
25308 * Copyright(c) 2006-2007, Ext JS, LLC.
25310 * Originally Released Under LGPL - original licence link has changed is not relivant.
25313 * <script type="text/javascript">
25317 * @class Roo.data.ArrayReader
25318 * @extends Roo.data.DataReader
25319 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25320 * Each element of that Array represents a row of data fields. The
25321 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25322 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25326 var RecordDef = Roo.data.Record.create([
25327 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25328 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25330 var myReader = new Roo.data.ArrayReader({
25331 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25335 * This would consume an Array like this:
25337 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25341 * Create a new JsonReader
25342 * @param {Object} meta Metadata configuration options.
25343 * @param {Object|Array} recordType Either an Array of field definition objects
25345 * @cfg {Array} fields Array of field definition objects
25346 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25347 * as specified to {@link Roo.data.Record#create},
25348 * or an {@link Roo.data.Record} object
25351 * created using {@link Roo.data.Record#create}.
25353 Roo.data.ArrayReader = function(meta, recordType)
25355 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25358 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25361 * Create a data block containing Roo.data.Records from an XML document.
25362 * @param {Object} o An Array of row objects which represents the dataset.
25363 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25364 * a cache of Roo.data.Records.
25366 readRecords : function(o)
25368 var sid = this.meta ? this.meta.id : null;
25369 var recordType = this.recordType, fields = recordType.prototype.fields;
25372 for(var i = 0; i < root.length; i++){
25375 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25376 for(var j = 0, jlen = fields.length; j < jlen; j++){
25377 var f = fields.items[j];
25378 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25379 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25381 values[f.name] = v;
25383 var record = new recordType(values, id);
25385 records[records.length] = record;
25389 totalRecords : records.length
25392 // used when loading children.. @see loadDataFromChildren
25393 toLoadData: function(rec)
25395 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25396 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25403 * Ext JS Library 1.1.1
25404 * Copyright(c) 2006-2007, Ext JS, LLC.
25406 * Originally Released Under LGPL - original licence link has changed is not relivant.
25409 * <script type="text/javascript">
25414 * @class Roo.data.Tree
25415 * @extends Roo.util.Observable
25416 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25417 * in the tree have most standard DOM functionality.
25419 * @param {Node} root (optional) The root node
25421 Roo.data.Tree = function(root){
25422 this.nodeHash = {};
25424 * The root node for this tree
25429 this.setRootNode(root);
25434 * Fires when a new child node is appended to a node in this tree.
25435 * @param {Tree} tree The owner tree
25436 * @param {Node} parent The parent node
25437 * @param {Node} node The newly appended node
25438 * @param {Number} index The index of the newly appended node
25443 * Fires when a child node is removed from a node in this tree.
25444 * @param {Tree} tree The owner tree
25445 * @param {Node} parent The parent node
25446 * @param {Node} node The child node removed
25451 * Fires when a node is moved to a new location in the tree
25452 * @param {Tree} tree The owner tree
25453 * @param {Node} node The node moved
25454 * @param {Node} oldParent The old parent of this node
25455 * @param {Node} newParent The new parent of this node
25456 * @param {Number} index The index it was moved to
25461 * Fires when a new child node is inserted in a node in this tree.
25462 * @param {Tree} tree The owner tree
25463 * @param {Node} parent The parent node
25464 * @param {Node} node The child node inserted
25465 * @param {Node} refNode The child node the node was inserted before
25469 * @event beforeappend
25470 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25471 * @param {Tree} tree The owner tree
25472 * @param {Node} parent The parent node
25473 * @param {Node} node The child node to be appended
25475 "beforeappend" : true,
25477 * @event beforeremove
25478 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25479 * @param {Tree} tree The owner tree
25480 * @param {Node} parent The parent node
25481 * @param {Node} node The child node to be removed
25483 "beforeremove" : true,
25485 * @event beforemove
25486 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25487 * @param {Tree} tree The owner tree
25488 * @param {Node} node The node being moved
25489 * @param {Node} oldParent The parent of the node
25490 * @param {Node} newParent The new parent the node is moving to
25491 * @param {Number} index The index it is being moved to
25493 "beforemove" : true,
25495 * @event beforeinsert
25496 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25497 * @param {Tree} tree The owner tree
25498 * @param {Node} parent The parent node
25499 * @param {Node} node The child node to be inserted
25500 * @param {Node} refNode The child node the node is being inserted before
25502 "beforeinsert" : true
25505 Roo.data.Tree.superclass.constructor.call(this);
25508 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25509 pathSeparator: "/",
25511 proxyNodeEvent : function(){
25512 return this.fireEvent.apply(this, arguments);
25516 * Returns the root node for this tree.
25519 getRootNode : function(){
25524 * Sets the root node for this tree.
25525 * @param {Node} node
25528 setRootNode : function(node){
25530 node.ownerTree = this;
25531 node.isRoot = true;
25532 this.registerNode(node);
25537 * Gets a node in this tree by its id.
25538 * @param {String} id
25541 getNodeById : function(id){
25542 return this.nodeHash[id];
25545 registerNode : function(node){
25546 this.nodeHash[node.id] = node;
25549 unregisterNode : function(node){
25550 delete this.nodeHash[node.id];
25553 toString : function(){
25554 return "[Tree"+(this.id?" "+this.id:"")+"]";
25559 * @class Roo.data.Node
25560 * @extends Roo.util.Observable
25561 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25562 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25564 * @param {Object} attributes The attributes/config for the node
25566 Roo.data.Node = function(attributes){
25568 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25571 this.attributes = attributes || {};
25572 this.leaf = this.attributes.leaf;
25574 * The node id. @type String
25576 this.id = this.attributes.id;
25578 this.id = Roo.id(null, "ynode-");
25579 this.attributes.id = this.id;
25584 * All child nodes of this node. @type Array
25586 this.childNodes = [];
25587 if(!this.childNodes.indexOf){ // indexOf is a must
25588 this.childNodes.indexOf = function(o){
25589 for(var i = 0, len = this.length; i < len; i++){
25598 * The parent node for this node. @type Node
25600 this.parentNode = null;
25602 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25604 this.firstChild = null;
25606 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25608 this.lastChild = null;
25610 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25612 this.previousSibling = null;
25614 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25616 this.nextSibling = null;
25621 * Fires when a new child node is appended
25622 * @param {Tree} tree The owner tree
25623 * @param {Node} this This node
25624 * @param {Node} node The newly appended node
25625 * @param {Number} index The index of the newly appended node
25630 * Fires when a child node is removed
25631 * @param {Tree} tree The owner tree
25632 * @param {Node} this This node
25633 * @param {Node} node The removed node
25638 * Fires when this node is moved to a new location in the tree
25639 * @param {Tree} tree The owner tree
25640 * @param {Node} this This node
25641 * @param {Node} oldParent The old parent of this node
25642 * @param {Node} newParent The new parent of this node
25643 * @param {Number} index The index it was moved to
25648 * Fires when a new child node is inserted.
25649 * @param {Tree} tree The owner tree
25650 * @param {Node} this This node
25651 * @param {Node} node The child node inserted
25652 * @param {Node} refNode The child node the node was inserted before
25656 * @event beforeappend
25657 * Fires before a new child is appended, return false to cancel the append.
25658 * @param {Tree} tree The owner tree
25659 * @param {Node} this This node
25660 * @param {Node} node The child node to be appended
25662 "beforeappend" : true,
25664 * @event beforeremove
25665 * Fires before a child is removed, return false to cancel the remove.
25666 * @param {Tree} tree The owner tree
25667 * @param {Node} this This node
25668 * @param {Node} node The child node to be removed
25670 "beforeremove" : true,
25672 * @event beforemove
25673 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25674 * @param {Tree} tree The owner tree
25675 * @param {Node} this This node
25676 * @param {Node} oldParent The parent of this node
25677 * @param {Node} newParent The new parent this node is moving to
25678 * @param {Number} index The index it is being moved to
25680 "beforemove" : true,
25682 * @event beforeinsert
25683 * Fires before a new child is inserted, return false to cancel the insert.
25684 * @param {Tree} tree The owner tree
25685 * @param {Node} this This node
25686 * @param {Node} node The child node to be inserted
25687 * @param {Node} refNode The child node the node is being inserted before
25689 "beforeinsert" : true
25691 this.listeners = this.attributes.listeners;
25692 Roo.data.Node.superclass.constructor.call(this);
25695 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25696 fireEvent : function(evtName){
25697 // first do standard event for this node
25698 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25701 // then bubble it up to the tree if the event wasn't cancelled
25702 var ot = this.getOwnerTree();
25704 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25712 * Returns true if this node is a leaf
25713 * @return {Boolean}
25715 isLeaf : function(){
25716 return this.leaf === true;
25720 setFirstChild : function(node){
25721 this.firstChild = node;
25725 setLastChild : function(node){
25726 this.lastChild = node;
25731 * Returns true if this node is the last child of its parent
25732 * @return {Boolean}
25734 isLast : function(){
25735 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25739 * Returns true if this node is the first child of its parent
25740 * @return {Boolean}
25742 isFirst : function(){
25743 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25746 hasChildNodes : function(){
25747 return !this.isLeaf() && this.childNodes.length > 0;
25751 * Insert node(s) as the last child node of this node.
25752 * @param {Node/Array} node The node or Array of nodes to append
25753 * @return {Node} The appended node if single append, or null if an array was passed
25755 appendChild : function(node){
25757 if(node instanceof Array){
25759 }else if(arguments.length > 1){
25763 // if passed an array or multiple args do them one by one
25765 for(var i = 0, len = multi.length; i < len; i++) {
25766 this.appendChild(multi[i]);
25769 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25772 var index = this.childNodes.length;
25773 var oldParent = node.parentNode;
25774 // it's a move, make sure we move it cleanly
25776 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25779 oldParent.removeChild(node);
25782 index = this.childNodes.length;
25784 this.setFirstChild(node);
25786 this.childNodes.push(node);
25787 node.parentNode = this;
25788 var ps = this.childNodes[index-1];
25790 node.previousSibling = ps;
25791 ps.nextSibling = node;
25793 node.previousSibling = null;
25795 node.nextSibling = null;
25796 this.setLastChild(node);
25797 node.setOwnerTree(this.getOwnerTree());
25798 this.fireEvent("append", this.ownerTree, this, node, index);
25799 if(this.ownerTree) {
25800 this.ownerTree.fireEvent("appendnode", this, node, index);
25803 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25810 * Removes a child node from this node.
25811 * @param {Node} node The node to remove
25812 * @return {Node} The removed node
25814 removeChild : function(node){
25815 var index = this.childNodes.indexOf(node);
25819 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25823 // remove it from childNodes collection
25824 this.childNodes.splice(index, 1);
25827 if(node.previousSibling){
25828 node.previousSibling.nextSibling = node.nextSibling;
25830 if(node.nextSibling){
25831 node.nextSibling.previousSibling = node.previousSibling;
25834 // update child refs
25835 if(this.firstChild == node){
25836 this.setFirstChild(node.nextSibling);
25838 if(this.lastChild == node){
25839 this.setLastChild(node.previousSibling);
25842 node.setOwnerTree(null);
25843 // clear any references from the node
25844 node.parentNode = null;
25845 node.previousSibling = null;
25846 node.nextSibling = null;
25847 this.fireEvent("remove", this.ownerTree, this, node);
25852 * Inserts the first node before the second node in this nodes childNodes collection.
25853 * @param {Node} node The node to insert
25854 * @param {Node} refNode The node to insert before (if null the node is appended)
25855 * @return {Node} The inserted node
25857 insertBefore : function(node, refNode){
25858 if(!refNode){ // like standard Dom, refNode can be null for append
25859 return this.appendChild(node);
25862 if(node == refNode){
25866 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25869 var index = this.childNodes.indexOf(refNode);
25870 var oldParent = node.parentNode;
25871 var refIndex = index;
25873 // when moving internally, indexes will change after remove
25874 if(oldParent == this && this.childNodes.indexOf(node) < index){
25878 // it's a move, make sure we move it cleanly
25880 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25883 oldParent.removeChild(node);
25886 this.setFirstChild(node);
25888 this.childNodes.splice(refIndex, 0, node);
25889 node.parentNode = this;
25890 var ps = this.childNodes[refIndex-1];
25892 node.previousSibling = ps;
25893 ps.nextSibling = node;
25895 node.previousSibling = null;
25897 node.nextSibling = refNode;
25898 refNode.previousSibling = node;
25899 node.setOwnerTree(this.getOwnerTree());
25900 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25902 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25908 * Returns the child node at the specified index.
25909 * @param {Number} index
25912 item : function(index){
25913 return this.childNodes[index];
25917 * Replaces one child node in this node with another.
25918 * @param {Node} newChild The replacement node
25919 * @param {Node} oldChild The node to replace
25920 * @return {Node} The replaced node
25922 replaceChild : function(newChild, oldChild){
25923 this.insertBefore(newChild, oldChild);
25924 this.removeChild(oldChild);
25929 * Returns the index of a child node
25930 * @param {Node} node
25931 * @return {Number} The index of the node or -1 if it was not found
25933 indexOf : function(child){
25934 return this.childNodes.indexOf(child);
25938 * Returns the tree this node is in.
25941 getOwnerTree : function(){
25942 // if it doesn't have one, look for one
25943 if(!this.ownerTree){
25947 this.ownerTree = p.ownerTree;
25953 return this.ownerTree;
25957 * Returns depth of this node (the root node has a depth of 0)
25960 getDepth : function(){
25963 while(p.parentNode){
25971 setOwnerTree : function(tree){
25972 // if it's move, we need to update everyone
25973 if(tree != this.ownerTree){
25974 if(this.ownerTree){
25975 this.ownerTree.unregisterNode(this);
25977 this.ownerTree = tree;
25978 var cs = this.childNodes;
25979 for(var i = 0, len = cs.length; i < len; i++) {
25980 cs[i].setOwnerTree(tree);
25983 tree.registerNode(this);
25989 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25990 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25991 * @return {String} The path
25993 getPath : function(attr){
25994 attr = attr || "id";
25995 var p = this.parentNode;
25996 var b = [this.attributes[attr]];
25998 b.unshift(p.attributes[attr]);
26001 var sep = this.getOwnerTree().pathSeparator;
26002 return sep + b.join(sep);
26006 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26007 * function call will be the scope provided or the current node. The arguments to the function
26008 * will be the args provided or the current node. If the function returns false at any point,
26009 * the bubble is stopped.
26010 * @param {Function} fn The function to call
26011 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26012 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26014 bubble : function(fn, scope, args){
26017 if(fn.call(scope || p, args || p) === false){
26025 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26026 * function call will be the scope provided or the current node. The arguments to the function
26027 * will be the args provided or the current node. If the function returns false at any point,
26028 * the cascade is stopped on that branch.
26029 * @param {Function} fn The function to call
26030 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26031 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26033 cascade : function(fn, scope, args){
26034 if(fn.call(scope || this, args || this) !== false){
26035 var cs = this.childNodes;
26036 for(var i = 0, len = cs.length; i < len; i++) {
26037 cs[i].cascade(fn, scope, args);
26043 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
26044 * function call will be the scope provided or the current node. The arguments to the function
26045 * will be the args provided or the current node. If the function returns false at any point,
26046 * the iteration stops.
26047 * @param {Function} fn The function to call
26048 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26049 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26051 eachChild : function(fn, scope, args){
26052 var cs = this.childNodes;
26053 for(var i = 0, len = cs.length; i < len; i++) {
26054 if(fn.call(scope || this, args || cs[i]) === false){
26061 * Finds the first child that has the attribute with the specified value.
26062 * @param {String} attribute The attribute name
26063 * @param {Mixed} value The value to search for
26064 * @return {Node} The found child or null if none was found
26066 findChild : function(attribute, value){
26067 var cs = this.childNodes;
26068 for(var i = 0, len = cs.length; i < len; i++) {
26069 if(cs[i].attributes[attribute] == value){
26077 * Finds the first child by a custom function. The child matches if the function passed
26079 * @param {Function} fn
26080 * @param {Object} scope (optional)
26081 * @return {Node} The found child or null if none was found
26083 findChildBy : function(fn, scope){
26084 var cs = this.childNodes;
26085 for(var i = 0, len = cs.length; i < len; i++) {
26086 if(fn.call(scope||cs[i], cs[i]) === true){
26094 * Sorts this nodes children using the supplied sort function
26095 * @param {Function} fn
26096 * @param {Object} scope (optional)
26098 sort : function(fn, scope){
26099 var cs = this.childNodes;
26100 var len = cs.length;
26102 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
26104 for(var i = 0; i < len; i++){
26106 n.previousSibling = cs[i-1];
26107 n.nextSibling = cs[i+1];
26109 this.setFirstChild(n);
26112 this.setLastChild(n);
26119 * Returns true if this node is an ancestor (at any point) of the passed node.
26120 * @param {Node} node
26121 * @return {Boolean}
26123 contains : function(node){
26124 return node.isAncestor(this);
26128 * Returns true if the passed node is an ancestor (at any point) of this node.
26129 * @param {Node} node
26130 * @return {Boolean}
26132 isAncestor : function(node){
26133 var p = this.parentNode;
26143 toString : function(){
26144 return "[Node"+(this.id?" "+this.id:"")+"]";
26148 * Ext JS Library 1.1.1
26149 * Copyright(c) 2006-2007, Ext JS, LLC.
26151 * Originally Released Under LGPL - original licence link has changed is not relivant.
26154 * <script type="text/javascript">
26159 * @class Roo.Shadow
26160 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26161 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26162 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26164 * Create a new Shadow
26165 * @param {Object} config The config object
26167 Roo.Shadow = function(config){
26168 Roo.apply(this, config);
26169 if(typeof this.mode != "string"){
26170 this.mode = this.defaultMode;
26172 var o = this.offset, a = {h: 0};
26173 var rad = Math.floor(this.offset/2);
26174 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26180 a.l -= this.offset + rad;
26181 a.t -= this.offset + rad;
26192 a.l -= (this.offset - rad);
26193 a.t -= this.offset + rad;
26195 a.w -= (this.offset - rad)*2;
26206 a.l -= (this.offset - rad);
26207 a.t -= (this.offset - rad);
26209 a.w -= (this.offset + rad + 1);
26210 a.h -= (this.offset + rad);
26219 Roo.Shadow.prototype = {
26221 * @cfg {String} mode
26222 * The shadow display mode. Supports the following options:<br />
26223 * sides: Shadow displays on both sides and bottom only<br />
26224 * frame: Shadow displays equally on all four sides<br />
26225 * drop: Traditional bottom-right drop shadow (default)
26229 * @cfg {String} offset
26230 * The number of pixels to offset the shadow from the element (defaults to 4)
26235 defaultMode: "drop",
26238 * Displays the shadow under the target element
26239 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26241 show : function(target){
26242 target = Roo.get(target);
26244 this.el = Roo.Shadow.Pool.pull();
26245 if(this.el.dom.nextSibling != target.dom){
26246 this.el.insertBefore(target);
26249 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26251 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26254 target.getLeft(true),
26255 target.getTop(true),
26259 this.el.dom.style.display = "block";
26263 * Returns true if the shadow is visible, else false
26265 isVisible : function(){
26266 return this.el ? true : false;
26270 * Direct alignment when values are already available. Show must be called at least once before
26271 * calling this method to ensure it is initialized.
26272 * @param {Number} left The target element left position
26273 * @param {Number} top The target element top position
26274 * @param {Number} width The target element width
26275 * @param {Number} height The target element height
26277 realign : function(l, t, w, h){
26281 var a = this.adjusts, d = this.el.dom, s = d.style;
26283 s.left = (l+a.l)+"px";
26284 s.top = (t+a.t)+"px";
26285 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26287 if(s.width != sws || s.height != shs){
26291 var cn = d.childNodes;
26292 var sww = Math.max(0, (sw-12))+"px";
26293 cn[0].childNodes[1].style.width = sww;
26294 cn[1].childNodes[1].style.width = sww;
26295 cn[2].childNodes[1].style.width = sww;
26296 cn[1].style.height = Math.max(0, (sh-12))+"px";
26302 * Hides this shadow
26306 this.el.dom.style.display = "none";
26307 Roo.Shadow.Pool.push(this.el);
26313 * Adjust the z-index of this shadow
26314 * @param {Number} zindex The new z-index
26316 setZIndex : function(z){
26319 this.el.setStyle("z-index", z);
26324 // Private utility class that manages the internal Shadow cache
26325 Roo.Shadow.Pool = function(){
26327 var markup = Roo.isIE ?
26328 '<div class="x-ie-shadow"></div>' :
26329 '<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>';
26332 var sh = p.shift();
26334 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26335 sh.autoBoxAdjust = false;
26340 push : function(sh){
26346 * Ext JS Library 1.1.1
26347 * Copyright(c) 2006-2007, Ext JS, LLC.
26349 * Originally Released Under LGPL - original licence link has changed is not relivant.
26352 * <script type="text/javascript">
26357 * @class Roo.SplitBar
26358 * @extends Roo.util.Observable
26359 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26363 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26364 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26365 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26366 split.minSize = 100;
26367 split.maxSize = 600;
26368 split.animate = true;
26369 split.on('moved', splitterMoved);
26372 * Create a new SplitBar
26373 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26374 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26375 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26376 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26377 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26378 position of the SplitBar).
26380 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26383 this.el = Roo.get(dragElement, true);
26384 this.el.dom.unselectable = "on";
26386 this.resizingEl = Roo.get(resizingElement, true);
26390 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26391 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26394 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26397 * The minimum size of the resizing element. (Defaults to 0)
26403 * The maximum size of the resizing element. (Defaults to 2000)
26406 this.maxSize = 2000;
26409 * Whether to animate the transition to the new size
26412 this.animate = false;
26415 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26418 this.useShim = false;
26423 if(!existingProxy){
26425 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26427 this.proxy = Roo.get(existingProxy).dom;
26430 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26433 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26436 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26439 this.dragSpecs = {};
26442 * @private The adapter to use to positon and resize elements
26444 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26445 this.adapter.init(this);
26447 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26449 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26450 this.el.addClass("x-splitbar-h");
26453 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26454 this.el.addClass("x-splitbar-v");
26460 * Fires when the splitter is moved (alias for {@link #event-moved})
26461 * @param {Roo.SplitBar} this
26462 * @param {Number} newSize the new width or height
26467 * Fires when the splitter is moved
26468 * @param {Roo.SplitBar} this
26469 * @param {Number} newSize the new width or height
26473 * @event beforeresize
26474 * Fires before the splitter is dragged
26475 * @param {Roo.SplitBar} this
26477 "beforeresize" : true,
26479 "beforeapply" : true
26482 Roo.util.Observable.call(this);
26485 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26486 onStartProxyDrag : function(x, y){
26487 this.fireEvent("beforeresize", this);
26489 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26491 o.enableDisplayMode("block");
26492 // all splitbars share the same overlay
26493 Roo.SplitBar.prototype.overlay = o;
26495 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26496 this.overlay.show();
26497 Roo.get(this.proxy).setDisplayed("block");
26498 var size = this.adapter.getElementSize(this);
26499 this.activeMinSize = this.getMinimumSize();;
26500 this.activeMaxSize = this.getMaximumSize();;
26501 var c1 = size - this.activeMinSize;
26502 var c2 = Math.max(this.activeMaxSize - size, 0);
26503 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26504 this.dd.resetConstraints();
26505 this.dd.setXConstraint(
26506 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26507 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26509 this.dd.setYConstraint(0, 0);
26511 this.dd.resetConstraints();
26512 this.dd.setXConstraint(0, 0);
26513 this.dd.setYConstraint(
26514 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26515 this.placement == Roo.SplitBar.TOP ? c2 : c1
26518 this.dragSpecs.startSize = size;
26519 this.dragSpecs.startPoint = [x, y];
26520 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26524 * @private Called after the drag operation by the DDProxy
26526 onEndProxyDrag : function(e){
26527 Roo.get(this.proxy).setDisplayed(false);
26528 var endPoint = Roo.lib.Event.getXY(e);
26530 this.overlay.hide();
26533 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26534 newSize = this.dragSpecs.startSize +
26535 (this.placement == Roo.SplitBar.LEFT ?
26536 endPoint[0] - this.dragSpecs.startPoint[0] :
26537 this.dragSpecs.startPoint[0] - endPoint[0]
26540 newSize = this.dragSpecs.startSize +
26541 (this.placement == Roo.SplitBar.TOP ?
26542 endPoint[1] - this.dragSpecs.startPoint[1] :
26543 this.dragSpecs.startPoint[1] - endPoint[1]
26546 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26547 if(newSize != this.dragSpecs.startSize){
26548 if(this.fireEvent('beforeapply', this, newSize) !== false){
26549 this.adapter.setElementSize(this, newSize);
26550 this.fireEvent("moved", this, newSize);
26551 this.fireEvent("resize", this, newSize);
26557 * Get the adapter this SplitBar uses
26558 * @return The adapter object
26560 getAdapter : function(){
26561 return this.adapter;
26565 * Set the adapter this SplitBar uses
26566 * @param {Object} adapter A SplitBar adapter object
26568 setAdapter : function(adapter){
26569 this.adapter = adapter;
26570 this.adapter.init(this);
26574 * Gets the minimum size for the resizing element
26575 * @return {Number} The minimum size
26577 getMinimumSize : function(){
26578 return this.minSize;
26582 * Sets the minimum size for the resizing element
26583 * @param {Number} minSize The minimum size
26585 setMinimumSize : function(minSize){
26586 this.minSize = minSize;
26590 * Gets the maximum size for the resizing element
26591 * @return {Number} The maximum size
26593 getMaximumSize : function(){
26594 return this.maxSize;
26598 * Sets the maximum size for the resizing element
26599 * @param {Number} maxSize The maximum size
26601 setMaximumSize : function(maxSize){
26602 this.maxSize = maxSize;
26606 * Sets the initialize size for the resizing element
26607 * @param {Number} size The initial size
26609 setCurrentSize : function(size){
26610 var oldAnimate = this.animate;
26611 this.animate = false;
26612 this.adapter.setElementSize(this, size);
26613 this.animate = oldAnimate;
26617 * Destroy this splitbar.
26618 * @param {Boolean} removeEl True to remove the element
26620 destroy : function(removeEl){
26622 this.shim.remove();
26625 this.proxy.parentNode.removeChild(this.proxy);
26633 * @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.
26635 Roo.SplitBar.createProxy = function(dir){
26636 var proxy = new Roo.Element(document.createElement("div"));
26637 proxy.unselectable();
26638 var cls = 'x-splitbar-proxy';
26639 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26640 document.body.appendChild(proxy.dom);
26645 * @class Roo.SplitBar.BasicLayoutAdapter
26646 * Default Adapter. It assumes the splitter and resizing element are not positioned
26647 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26649 Roo.SplitBar.BasicLayoutAdapter = function(){
26652 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26653 // do nothing for now
26654 init : function(s){
26658 * Called before drag operations to get the current size of the resizing element.
26659 * @param {Roo.SplitBar} s The SplitBar using this adapter
26661 getElementSize : function(s){
26662 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26663 return s.resizingEl.getWidth();
26665 return s.resizingEl.getHeight();
26670 * Called after drag operations to set the size of the resizing element.
26671 * @param {Roo.SplitBar} s The SplitBar using this adapter
26672 * @param {Number} newSize The new size to set
26673 * @param {Function} onComplete A function to be invoked when resizing is complete
26675 setElementSize : function(s, newSize, onComplete){
26676 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26678 s.resizingEl.setWidth(newSize);
26680 onComplete(s, newSize);
26683 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26688 s.resizingEl.setHeight(newSize);
26690 onComplete(s, newSize);
26693 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26700 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26701 * @extends Roo.SplitBar.BasicLayoutAdapter
26702 * Adapter that moves the splitter element to align with the resized sizing element.
26703 * Used with an absolute positioned SplitBar.
26704 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26705 * document.body, make sure you assign an id to the body element.
26707 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26708 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26709 this.container = Roo.get(container);
26712 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26713 init : function(s){
26714 this.basic.init(s);
26717 getElementSize : function(s){
26718 return this.basic.getElementSize(s);
26721 setElementSize : function(s, newSize, onComplete){
26722 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26725 moveSplitter : function(s){
26726 var yes = Roo.SplitBar;
26727 switch(s.placement){
26729 s.el.setX(s.resizingEl.getRight());
26732 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26735 s.el.setY(s.resizingEl.getBottom());
26738 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26745 * Orientation constant - Create a vertical SplitBar
26749 Roo.SplitBar.VERTICAL = 1;
26752 * Orientation constant - Create a horizontal SplitBar
26756 Roo.SplitBar.HORIZONTAL = 2;
26759 * Placement constant - The resizing element is to the left of the splitter element
26763 Roo.SplitBar.LEFT = 1;
26766 * Placement constant - The resizing element is to the right of the splitter element
26770 Roo.SplitBar.RIGHT = 2;
26773 * Placement constant - The resizing element is positioned above the splitter element
26777 Roo.SplitBar.TOP = 3;
26780 * Placement constant - The resizing element is positioned under splitter element
26784 Roo.SplitBar.BOTTOM = 4;
26787 * Ext JS Library 1.1.1
26788 * Copyright(c) 2006-2007, Ext JS, LLC.
26790 * Originally Released Under LGPL - original licence link has changed is not relivant.
26793 * <script type="text/javascript">
26798 * @extends Roo.util.Observable
26799 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26800 * This class also supports single and multi selection modes. <br>
26801 * Create a data model bound view:
26803 var store = new Roo.data.Store(...);
26805 var view = new Roo.View({
26807 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26809 singleSelect: true,
26810 selectedClass: "ydataview-selected",
26814 // listen for node click?
26815 view.on("click", function(vw, index, node, e){
26816 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26820 dataModel.load("foobar.xml");
26822 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26824 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26825 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26827 * Note: old style constructor is still suported (container, template, config)
26830 * Create a new View
26831 * @param {Object} config The config object
26834 Roo.View = function(config, depreciated_tpl, depreciated_config){
26836 this.parent = false;
26838 if (typeof(depreciated_tpl) == 'undefined') {
26839 // new way.. - universal constructor.
26840 Roo.apply(this, config);
26841 this.el = Roo.get(this.el);
26844 this.el = Roo.get(config);
26845 this.tpl = depreciated_tpl;
26846 Roo.apply(this, depreciated_config);
26848 this.wrapEl = this.el.wrap().wrap();
26849 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26852 if(typeof(this.tpl) == "string"){
26853 this.tpl = new Roo.Template(this.tpl);
26855 // support xtype ctors..
26856 this.tpl = new Roo.factory(this.tpl, Roo);
26860 this.tpl.compile();
26865 * @event beforeclick
26866 * Fires before a click is processed. Returns false to cancel the default action.
26867 * @param {Roo.View} this
26868 * @param {Number} index The index of the target node
26869 * @param {HTMLElement} node The target node
26870 * @param {Roo.EventObject} e The raw event object
26872 "beforeclick" : true,
26875 * Fires when a template node is clicked.
26876 * @param {Roo.View} this
26877 * @param {Number} index The index of the target node
26878 * @param {HTMLElement} node The target node
26879 * @param {Roo.EventObject} e The raw event object
26884 * Fires when a template node is double clicked.
26885 * @param {Roo.View} this
26886 * @param {Number} index The index of the target node
26887 * @param {HTMLElement} node The target node
26888 * @param {Roo.EventObject} e The raw event object
26892 * @event contextmenu
26893 * Fires when a template node is right clicked.
26894 * @param {Roo.View} this
26895 * @param {Number} index The index of the target node
26896 * @param {HTMLElement} node The target node
26897 * @param {Roo.EventObject} e The raw event object
26899 "contextmenu" : true,
26901 * @event selectionchange
26902 * Fires when the selected nodes change.
26903 * @param {Roo.View} this
26904 * @param {Array} selections Array of the selected nodes
26906 "selectionchange" : true,
26909 * @event beforeselect
26910 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26911 * @param {Roo.View} this
26912 * @param {HTMLElement} node The node to be selected
26913 * @param {Array} selections Array of currently selected nodes
26915 "beforeselect" : true,
26917 * @event preparedata
26918 * Fires on every row to render, to allow you to change the data.
26919 * @param {Roo.View} this
26920 * @param {Object} data to be rendered (change this)
26922 "preparedata" : true
26930 "click": this.onClick,
26931 "dblclick": this.onDblClick,
26932 "contextmenu": this.onContextMenu,
26936 this.selections = [];
26938 this.cmp = new Roo.CompositeElementLite([]);
26940 this.store = Roo.factory(this.store, Roo.data);
26941 this.setStore(this.store, true);
26944 if ( this.footer && this.footer.xtype) {
26946 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26948 this.footer.dataSource = this.store;
26949 this.footer.container = fctr;
26950 this.footer = Roo.factory(this.footer, Roo);
26951 fctr.insertFirst(this.el);
26953 // this is a bit insane - as the paging toolbar seems to detach the el..
26954 // dom.parentNode.parentNode.parentNode
26955 // they get detached?
26959 Roo.View.superclass.constructor.call(this);
26964 Roo.extend(Roo.View, Roo.util.Observable, {
26967 * @cfg {Roo.data.Store} store Data store to load data from.
26972 * @cfg {String|Roo.Element} el The container element.
26977 * @cfg {String|Roo.Template} tpl The template used by this View
26981 * @cfg {String} dataName the named area of the template to use as the data area
26982 * Works with domtemplates roo-name="name"
26986 * @cfg {String} selectedClass The css class to add to selected nodes
26988 selectedClass : "x-view-selected",
26990 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26995 * @cfg {String} text to display on mask (default Loading)
26999 * @cfg {Boolean} multiSelect Allow multiple selection
27001 multiSelect : false,
27003 * @cfg {Boolean} singleSelect Allow single selection
27005 singleSelect: false,
27008 * @cfg {Boolean} toggleSelect - selecting
27010 toggleSelect : false,
27013 * @cfg {Boolean} tickable - selecting
27018 * Returns the element this view is bound to.
27019 * @return {Roo.Element}
27021 getEl : function(){
27022 return this.wrapEl;
27028 * Refreshes the view. - called by datachanged on the store. - do not call directly.
27030 refresh : function(){
27031 //Roo.log('refresh');
27034 // if we are using something like 'domtemplate', then
27035 // the what gets used is:
27036 // t.applySubtemplate(NAME, data, wrapping data..)
27037 // the outer template then get' applied with
27038 // the store 'extra data'
27039 // and the body get's added to the
27040 // roo-name="data" node?
27041 // <span class='roo-tpl-{name}'></span> ?????
27045 this.clearSelections();
27046 this.el.update("");
27048 var records = this.store.getRange();
27049 if(records.length < 1) {
27051 // is this valid?? = should it render a template??
27053 this.el.update(this.emptyText);
27057 if (this.dataName) {
27058 this.el.update(t.apply(this.store.meta)); //????
27059 el = this.el.child('.roo-tpl-' + this.dataName);
27062 for(var i = 0, len = records.length; i < len; i++){
27063 var data = this.prepareData(records[i].data, i, records[i]);
27064 this.fireEvent("preparedata", this, data, i, records[i]);
27066 var d = Roo.apply({}, data);
27069 Roo.apply(d, {'roo-id' : Roo.id()});
27073 Roo.each(this.parent.item, function(item){
27074 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
27077 Roo.apply(d, {'roo-data-checked' : 'checked'});
27081 html[html.length] = Roo.util.Format.trim(
27083 t.applySubtemplate(this.dataName, d, this.store.meta) :
27090 el.update(html.join(""));
27091 this.nodes = el.dom.childNodes;
27092 this.updateIndexes(0);
27097 * Function to override to reformat the data that is sent to
27098 * the template for each node.
27099 * DEPRICATED - use the preparedata event handler.
27100 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
27101 * a JSON object for an UpdateManager bound view).
27103 prepareData : function(data, index, record)
27105 this.fireEvent("preparedata", this, data, index, record);
27109 onUpdate : function(ds, record){
27110 // Roo.log('on update');
27111 this.clearSelections();
27112 var index = this.store.indexOf(record);
27113 var n = this.nodes[index];
27114 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
27115 n.parentNode.removeChild(n);
27116 this.updateIndexes(index, index);
27122 onAdd : function(ds, records, index)
27124 //Roo.log(['on Add', ds, records, index] );
27125 this.clearSelections();
27126 if(this.nodes.length == 0){
27130 var n = this.nodes[index];
27131 for(var i = 0, len = records.length; i < len; i++){
27132 var d = this.prepareData(records[i].data, i, records[i]);
27134 this.tpl.insertBefore(n, d);
27137 this.tpl.append(this.el, d);
27140 this.updateIndexes(index);
27143 onRemove : function(ds, record, index){
27144 // Roo.log('onRemove');
27145 this.clearSelections();
27146 var el = this.dataName ?
27147 this.el.child('.roo-tpl-' + this.dataName) :
27150 el.dom.removeChild(this.nodes[index]);
27151 this.updateIndexes(index);
27155 * Refresh an individual node.
27156 * @param {Number} index
27158 refreshNode : function(index){
27159 this.onUpdate(this.store, this.store.getAt(index));
27162 updateIndexes : function(startIndex, endIndex){
27163 var ns = this.nodes;
27164 startIndex = startIndex || 0;
27165 endIndex = endIndex || ns.length - 1;
27166 for(var i = startIndex; i <= endIndex; i++){
27167 ns[i].nodeIndex = i;
27172 * Changes the data store this view uses and refresh the view.
27173 * @param {Store} store
27175 setStore : function(store, initial){
27176 if(!initial && this.store){
27177 this.store.un("datachanged", this.refresh);
27178 this.store.un("add", this.onAdd);
27179 this.store.un("remove", this.onRemove);
27180 this.store.un("update", this.onUpdate);
27181 this.store.un("clear", this.refresh);
27182 this.store.un("beforeload", this.onBeforeLoad);
27183 this.store.un("load", this.onLoad);
27184 this.store.un("loadexception", this.onLoad);
27188 store.on("datachanged", this.refresh, this);
27189 store.on("add", this.onAdd, this);
27190 store.on("remove", this.onRemove, this);
27191 store.on("update", this.onUpdate, this);
27192 store.on("clear", this.refresh, this);
27193 store.on("beforeload", this.onBeforeLoad, this);
27194 store.on("load", this.onLoad, this);
27195 store.on("loadexception", this.onLoad, this);
27203 * onbeforeLoad - masks the loading area.
27206 onBeforeLoad : function(store,opts)
27208 //Roo.log('onBeforeLoad');
27210 this.el.update("");
27212 this.el.mask(this.mask ? this.mask : "Loading" );
27214 onLoad : function ()
27221 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27222 * @param {HTMLElement} node
27223 * @return {HTMLElement} The template node
27225 findItemFromChild : function(node){
27226 var el = this.dataName ?
27227 this.el.child('.roo-tpl-' + this.dataName,true) :
27230 if(!node || node.parentNode == el){
27233 var p = node.parentNode;
27234 while(p && p != el){
27235 if(p.parentNode == el){
27244 onClick : function(e){
27245 var item = this.findItemFromChild(e.getTarget());
27247 var index = this.indexOf(item);
27248 if(this.onItemClick(item, index, e) !== false){
27249 this.fireEvent("click", this, index, item, e);
27252 this.clearSelections();
27257 onContextMenu : function(e){
27258 var item = this.findItemFromChild(e.getTarget());
27260 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27265 onDblClick : function(e){
27266 var item = this.findItemFromChild(e.getTarget());
27268 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27272 onItemClick : function(item, index, e)
27274 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27277 if (this.toggleSelect) {
27278 var m = this.isSelected(item) ? 'unselect' : 'select';
27281 _t[m](item, true, false);
27284 if(this.multiSelect || this.singleSelect){
27285 if(this.multiSelect && e.shiftKey && this.lastSelection){
27286 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27288 this.select(item, this.multiSelect && e.ctrlKey);
27289 this.lastSelection = item;
27292 if(!this.tickable){
27293 e.preventDefault();
27301 * Get the number of selected nodes.
27304 getSelectionCount : function(){
27305 return this.selections.length;
27309 * Get the currently selected nodes.
27310 * @return {Array} An array of HTMLElements
27312 getSelectedNodes : function(){
27313 return this.selections;
27317 * Get the indexes of the selected nodes.
27320 getSelectedIndexes : function(){
27321 var indexes = [], s = this.selections;
27322 for(var i = 0, len = s.length; i < len; i++){
27323 indexes.push(s[i].nodeIndex);
27329 * Clear all selections
27330 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27332 clearSelections : function(suppressEvent){
27333 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27334 this.cmp.elements = this.selections;
27335 this.cmp.removeClass(this.selectedClass);
27336 this.selections = [];
27337 if(!suppressEvent){
27338 this.fireEvent("selectionchange", this, this.selections);
27344 * Returns true if the passed node is selected
27345 * @param {HTMLElement/Number} node The node or node index
27346 * @return {Boolean}
27348 isSelected : function(node){
27349 var s = this.selections;
27353 node = this.getNode(node);
27354 return s.indexOf(node) !== -1;
27359 * @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
27360 * @param {Boolean} keepExisting (optional) true to keep existing selections
27361 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27363 select : function(nodeInfo, keepExisting, suppressEvent){
27364 if(nodeInfo instanceof Array){
27366 this.clearSelections(true);
27368 for(var i = 0, len = nodeInfo.length; i < len; i++){
27369 this.select(nodeInfo[i], true, true);
27373 var node = this.getNode(nodeInfo);
27374 if(!node || this.isSelected(node)){
27375 return; // already selected.
27378 this.clearSelections(true);
27381 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27382 Roo.fly(node).addClass(this.selectedClass);
27383 this.selections.push(node);
27384 if(!suppressEvent){
27385 this.fireEvent("selectionchange", this, this.selections);
27393 * @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
27394 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27395 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27397 unselect : function(nodeInfo, keepExisting, suppressEvent)
27399 if(nodeInfo instanceof Array){
27400 Roo.each(this.selections, function(s) {
27401 this.unselect(s, nodeInfo);
27405 var node = this.getNode(nodeInfo);
27406 if(!node || !this.isSelected(node)){
27407 //Roo.log("not selected");
27408 return; // not selected.
27412 Roo.each(this.selections, function(s) {
27414 Roo.fly(node).removeClass(this.selectedClass);
27421 this.selections= ns;
27422 this.fireEvent("selectionchange", this, this.selections);
27426 * Gets a template node.
27427 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27428 * @return {HTMLElement} The node or null if it wasn't found
27430 getNode : function(nodeInfo){
27431 if(typeof nodeInfo == "string"){
27432 return document.getElementById(nodeInfo);
27433 }else if(typeof nodeInfo == "number"){
27434 return this.nodes[nodeInfo];
27440 * Gets a range template nodes.
27441 * @param {Number} startIndex
27442 * @param {Number} endIndex
27443 * @return {Array} An array of nodes
27445 getNodes : function(start, end){
27446 var ns = this.nodes;
27447 start = start || 0;
27448 end = typeof end == "undefined" ? ns.length - 1 : end;
27451 for(var i = start; i <= end; i++){
27455 for(var i = start; i >= end; i--){
27463 * Finds the index of the passed node
27464 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27465 * @return {Number} The index of the node or -1
27467 indexOf : function(node){
27468 node = this.getNode(node);
27469 if(typeof node.nodeIndex == "number"){
27470 return node.nodeIndex;
27472 var ns = this.nodes;
27473 for(var i = 0, len = ns.length; i < len; i++){
27483 * Ext JS Library 1.1.1
27484 * Copyright(c) 2006-2007, Ext JS, LLC.
27486 * Originally Released Under LGPL - original licence link has changed is not relivant.
27489 * <script type="text/javascript">
27493 * @class Roo.JsonView
27494 * @extends Roo.View
27495 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27497 var view = new Roo.JsonView({
27498 container: "my-element",
27499 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27504 // listen for node click?
27505 view.on("click", function(vw, index, node, e){
27506 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27509 // direct load of JSON data
27510 view.load("foobar.php");
27512 // Example from my blog list
27513 var tpl = new Roo.Template(
27514 '<div class="entry">' +
27515 '<a class="entry-title" href="{link}">{title}</a>' +
27516 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27517 "</div><hr />"
27520 var moreView = new Roo.JsonView({
27521 container : "entry-list",
27525 moreView.on("beforerender", this.sortEntries, this);
27527 url: "/blog/get-posts.php",
27528 params: "allposts=true",
27529 text: "Loading Blog Entries..."
27533 * Note: old code is supported with arguments : (container, template, config)
27537 * Create a new JsonView
27539 * @param {Object} config The config object
27542 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27545 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27547 var um = this.el.getUpdateManager();
27548 um.setRenderer(this);
27549 um.on("update", this.onLoad, this);
27550 um.on("failure", this.onLoadException, this);
27553 * @event beforerender
27554 * Fires before rendering of the downloaded JSON data.
27555 * @param {Roo.JsonView} this
27556 * @param {Object} data The JSON data loaded
27560 * Fires when data is loaded.
27561 * @param {Roo.JsonView} this
27562 * @param {Object} data The JSON data loaded
27563 * @param {Object} response The raw Connect response object
27566 * @event loadexception
27567 * Fires when loading fails.
27568 * @param {Roo.JsonView} this
27569 * @param {Object} response The raw Connect response object
27572 'beforerender' : true,
27574 'loadexception' : true
27577 Roo.extend(Roo.JsonView, Roo.View, {
27579 * @type {String} The root property in the loaded JSON object that contains the data
27584 * Refreshes the view.
27586 refresh : function(){
27587 this.clearSelections();
27588 this.el.update("");
27590 var o = this.jsonData;
27591 if(o && o.length > 0){
27592 for(var i = 0, len = o.length; i < len; i++){
27593 var data = this.prepareData(o[i], i, o);
27594 html[html.length] = this.tpl.apply(data);
27597 html.push(this.emptyText);
27599 this.el.update(html.join(""));
27600 this.nodes = this.el.dom.childNodes;
27601 this.updateIndexes(0);
27605 * 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.
27606 * @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:
27609 url: "your-url.php",
27610 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27611 callback: yourFunction,
27612 scope: yourObject, //(optional scope)
27615 text: "Loading...",
27620 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27621 * 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.
27622 * @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}
27623 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27624 * @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.
27627 var um = this.el.getUpdateManager();
27628 um.update.apply(um, arguments);
27631 // note - render is a standard framework call...
27632 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27633 render : function(el, response){
27635 this.clearSelections();
27636 this.el.update("");
27639 if (response != '') {
27640 o = Roo.util.JSON.decode(response.responseText);
27643 o = o[this.jsonRoot];
27649 * The current JSON data or null
27652 this.beforeRender();
27657 * Get the number of records in the current JSON dataset
27660 getCount : function(){
27661 return this.jsonData ? this.jsonData.length : 0;
27665 * Returns the JSON object for the specified node(s)
27666 * @param {HTMLElement/Array} node The node or an array of nodes
27667 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27668 * you get the JSON object for the node
27670 getNodeData : function(node){
27671 if(node instanceof Array){
27673 for(var i = 0, len = node.length; i < len; i++){
27674 data.push(this.getNodeData(node[i]));
27678 return this.jsonData[this.indexOf(node)] || null;
27681 beforeRender : function(){
27682 this.snapshot = this.jsonData;
27684 this.sort.apply(this, this.sortInfo);
27686 this.fireEvent("beforerender", this, this.jsonData);
27689 onLoad : function(el, o){
27690 this.fireEvent("load", this, this.jsonData, o);
27693 onLoadException : function(el, o){
27694 this.fireEvent("loadexception", this, o);
27698 * Filter the data by a specific property.
27699 * @param {String} property A property on your JSON objects
27700 * @param {String/RegExp} value Either string that the property values
27701 * should start with, or a RegExp to test against the property
27703 filter : function(property, value){
27706 var ss = this.snapshot;
27707 if(typeof value == "string"){
27708 var vlen = value.length;
27710 this.clearFilter();
27713 value = value.toLowerCase();
27714 for(var i = 0, len = ss.length; i < len; i++){
27716 if(o[property].substr(0, vlen).toLowerCase() == value){
27720 } else if(value.exec){ // regex?
27721 for(var i = 0, len = ss.length; i < len; i++){
27723 if(value.test(o[property])){
27730 this.jsonData = data;
27736 * Filter by a function. The passed function will be called with each
27737 * object in the current dataset. If the function returns true the value is kept,
27738 * otherwise it is filtered.
27739 * @param {Function} fn
27740 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27742 filterBy : function(fn, scope){
27745 var ss = this.snapshot;
27746 for(var i = 0, len = ss.length; i < len; i++){
27748 if(fn.call(scope || this, o)){
27752 this.jsonData = data;
27758 * Clears the current filter.
27760 clearFilter : function(){
27761 if(this.snapshot && this.jsonData != this.snapshot){
27762 this.jsonData = this.snapshot;
27769 * Sorts the data for this view and refreshes it.
27770 * @param {String} property A property on your JSON objects to sort on
27771 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27772 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27774 sort : function(property, dir, sortType){
27775 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27778 var dsc = dir && dir.toLowerCase() == "desc";
27779 var f = function(o1, o2){
27780 var v1 = sortType ? sortType(o1[p]) : o1[p];
27781 var v2 = sortType ? sortType(o2[p]) : o2[p];
27784 return dsc ? +1 : -1;
27785 } else if(v1 > v2){
27786 return dsc ? -1 : +1;
27791 this.jsonData.sort(f);
27793 if(this.jsonData != this.snapshot){
27794 this.snapshot.sort(f);
27800 * Ext JS Library 1.1.1
27801 * Copyright(c) 2006-2007, Ext JS, LLC.
27803 * Originally Released Under LGPL - original licence link has changed is not relivant.
27806 * <script type="text/javascript">
27811 * @class Roo.ColorPalette
27812 * @extends Roo.Component
27813 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27814 * Here's an example of typical usage:
27816 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27817 cp.render('my-div');
27819 cp.on('select', function(palette, selColor){
27820 // do something with selColor
27824 * Create a new ColorPalette
27825 * @param {Object} config The config object
27827 Roo.ColorPalette = function(config){
27828 Roo.ColorPalette.superclass.constructor.call(this, config);
27832 * Fires when a color is selected
27833 * @param {ColorPalette} this
27834 * @param {String} color The 6-digit color hex code (without the # symbol)
27840 this.on("select", this.handler, this.scope, true);
27843 Roo.extend(Roo.ColorPalette, Roo.Component, {
27845 * @cfg {String} itemCls
27846 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27848 itemCls : "x-color-palette",
27850 * @cfg {String} value
27851 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27852 * the hex codes are case-sensitive.
27855 clickEvent:'click',
27857 ctype: "Roo.ColorPalette",
27860 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27862 allowReselect : false,
27865 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27866 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27867 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27868 * of colors with the width setting until the box is symmetrical.</p>
27869 * <p>You can override individual colors if needed:</p>
27871 var cp = new Roo.ColorPalette();
27872 cp.colors[0] = "FF0000"; // change the first box to red
27875 Or you can provide a custom array of your own for complete control:
27877 var cp = new Roo.ColorPalette();
27878 cp.colors = ["000000", "993300", "333300"];
27883 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27884 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27885 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27886 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27887 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27891 onRender : function(container, position){
27892 var t = new Roo.MasterTemplate(
27893 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27895 var c = this.colors;
27896 for(var i = 0, len = c.length; i < len; i++){
27899 var el = document.createElement("div");
27900 el.className = this.itemCls;
27902 container.dom.insertBefore(el, position);
27903 this.el = Roo.get(el);
27904 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27905 if(this.clickEvent != 'click'){
27906 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27911 afterRender : function(){
27912 Roo.ColorPalette.superclass.afterRender.call(this);
27914 var s = this.value;
27921 handleClick : function(e, t){
27922 e.preventDefault();
27923 if(!this.disabled){
27924 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27925 this.select(c.toUpperCase());
27930 * Selects the specified color in the palette (fires the select event)
27931 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27933 select : function(color){
27934 color = color.replace("#", "");
27935 if(color != this.value || this.allowReselect){
27938 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27940 el.child("a.color-"+color).addClass("x-color-palette-sel");
27941 this.value = color;
27942 this.fireEvent("select", this, color);
27947 * Ext JS Library 1.1.1
27948 * Copyright(c) 2006-2007, Ext JS, LLC.
27950 * Originally Released Under LGPL - original licence link has changed is not relivant.
27953 * <script type="text/javascript">
27957 * @class Roo.DatePicker
27958 * @extends Roo.Component
27959 * Simple date picker class.
27961 * Create a new DatePicker
27962 * @param {Object} config The config object
27964 Roo.DatePicker = function(config){
27965 Roo.DatePicker.superclass.constructor.call(this, config);
27967 this.value = config && config.value ?
27968 config.value.clearTime() : new Date().clearTime();
27973 * Fires when a date is selected
27974 * @param {DatePicker} this
27975 * @param {Date} date The selected date
27979 * @event monthchange
27980 * Fires when the displayed month changes
27981 * @param {DatePicker} this
27982 * @param {Date} date The selected month
27984 'monthchange': true
27988 this.on("select", this.handler, this.scope || this);
27990 // build the disabledDatesRE
27991 if(!this.disabledDatesRE && this.disabledDates){
27992 var dd = this.disabledDates;
27994 for(var i = 0; i < dd.length; i++){
27996 if(i != dd.length-1) {
28000 this.disabledDatesRE = new RegExp(re + ")");
28004 Roo.extend(Roo.DatePicker, Roo.Component, {
28006 * @cfg {String} todayText
28007 * The text to display on the button that selects the current date (defaults to "Today")
28009 todayText : "Today",
28011 * @cfg {String} okText
28012 * The text to display on the ok button
28014 okText : " OK ", //   to give the user extra clicking room
28016 * @cfg {String} cancelText
28017 * The text to display on the cancel button
28019 cancelText : "Cancel",
28021 * @cfg {String} todayTip
28022 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
28024 todayTip : "{0} (Spacebar)",
28026 * @cfg {Date} minDate
28027 * Minimum allowable date (JavaScript date object, defaults to null)
28031 * @cfg {Date} maxDate
28032 * Maximum allowable date (JavaScript date object, defaults to null)
28036 * @cfg {String} minText
28037 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
28039 minText : "This date is before the minimum date",
28041 * @cfg {String} maxText
28042 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
28044 maxText : "This date is after the maximum date",
28046 * @cfg {String} format
28047 * The default date format string which can be overriden for localization support. The format must be
28048 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
28052 * @cfg {Array} disabledDays
28053 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
28055 disabledDays : null,
28057 * @cfg {String} disabledDaysText
28058 * The tooltip to display when the date falls on a disabled day (defaults to "")
28060 disabledDaysText : "",
28062 * @cfg {RegExp} disabledDatesRE
28063 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
28065 disabledDatesRE : null,
28067 * @cfg {String} disabledDatesText
28068 * The tooltip text to display when the date falls on a disabled date (defaults to "")
28070 disabledDatesText : "",
28072 * @cfg {Boolean} constrainToViewport
28073 * True to constrain the date picker to the viewport (defaults to true)
28075 constrainToViewport : true,
28077 * @cfg {Array} monthNames
28078 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
28080 monthNames : Date.monthNames,
28082 * @cfg {Array} dayNames
28083 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
28085 dayNames : Date.dayNames,
28087 * @cfg {String} nextText
28088 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
28090 nextText: 'Next Month (Control+Right)',
28092 * @cfg {String} prevText
28093 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
28095 prevText: 'Previous Month (Control+Left)',
28097 * @cfg {String} monthYearText
28098 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
28100 monthYearText: 'Choose a month (Control+Up/Down to move years)',
28102 * @cfg {Number} startDay
28103 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
28107 * @cfg {Bool} showClear
28108 * Show a clear button (usefull for date form elements that can be blank.)
28114 * Sets the value of the date field
28115 * @param {Date} value The date to set
28117 setValue : function(value){
28118 var old = this.value;
28120 if (typeof(value) == 'string') {
28122 value = Date.parseDate(value, this.format);
28125 value = new Date();
28128 this.value = value.clearTime(true);
28130 this.update(this.value);
28135 * Gets the current selected value of the date field
28136 * @return {Date} The selected date
28138 getValue : function(){
28143 focus : function(){
28145 this.update(this.activeDate);
28150 onRender : function(container, position){
28153 '<table cellspacing="0">',
28154 '<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>',
28155 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28156 var dn = this.dayNames;
28157 for(var i = 0; i < 7; i++){
28158 var d = this.startDay+i;
28162 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28164 m[m.length] = "</tr></thead><tbody><tr>";
28165 for(var i = 0; i < 42; i++) {
28166 if(i % 7 == 0 && i != 0){
28167 m[m.length] = "</tr><tr>";
28169 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28171 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28172 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28174 var el = document.createElement("div");
28175 el.className = "x-date-picker";
28176 el.innerHTML = m.join("");
28178 container.dom.insertBefore(el, position);
28180 this.el = Roo.get(el);
28181 this.eventEl = Roo.get(el.firstChild);
28183 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28184 handler: this.showPrevMonth,
28186 preventDefault:true,
28190 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28191 handler: this.showNextMonth,
28193 preventDefault:true,
28197 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28199 this.monthPicker = this.el.down('div.x-date-mp');
28200 this.monthPicker.enableDisplayMode('block');
28202 var kn = new Roo.KeyNav(this.eventEl, {
28203 "left" : function(e){
28205 this.showPrevMonth() :
28206 this.update(this.activeDate.add("d", -1));
28209 "right" : function(e){
28211 this.showNextMonth() :
28212 this.update(this.activeDate.add("d", 1));
28215 "up" : function(e){
28217 this.showNextYear() :
28218 this.update(this.activeDate.add("d", -7));
28221 "down" : function(e){
28223 this.showPrevYear() :
28224 this.update(this.activeDate.add("d", 7));
28227 "pageUp" : function(e){
28228 this.showNextMonth();
28231 "pageDown" : function(e){
28232 this.showPrevMonth();
28235 "enter" : function(e){
28236 e.stopPropagation();
28243 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28245 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28247 this.el.unselectable();
28249 this.cells = this.el.select("table.x-date-inner tbody td");
28250 this.textNodes = this.el.query("table.x-date-inner tbody span");
28252 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28254 tooltip: this.monthYearText
28257 this.mbtn.on('click', this.showMonthPicker, this);
28258 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28261 var today = (new Date()).dateFormat(this.format);
28263 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28264 if (this.showClear) {
28265 baseTb.add( new Roo.Toolbar.Fill());
28268 text: String.format(this.todayText, today),
28269 tooltip: String.format(this.todayTip, today),
28270 handler: this.selectToday,
28274 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28277 if (this.showClear) {
28279 baseTb.add( new Roo.Toolbar.Fill());
28282 cls: 'x-btn-icon x-btn-clear',
28283 handler: function() {
28285 this.fireEvent("select", this, '');
28295 this.update(this.value);
28298 createMonthPicker : function(){
28299 if(!this.monthPicker.dom.firstChild){
28300 var buf = ['<table border="0" cellspacing="0">'];
28301 for(var i = 0; i < 6; i++){
28303 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28304 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28306 '<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>' :
28307 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28311 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28313 '</button><button type="button" class="x-date-mp-cancel">',
28315 '</button></td></tr>',
28318 this.monthPicker.update(buf.join(''));
28319 this.monthPicker.on('click', this.onMonthClick, this);
28320 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28322 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28323 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28325 this.mpMonths.each(function(m, a, i){
28328 m.dom.xmonth = 5 + Math.round(i * .5);
28330 m.dom.xmonth = Math.round((i-1) * .5);
28336 showMonthPicker : function(){
28337 this.createMonthPicker();
28338 var size = this.el.getSize();
28339 this.monthPicker.setSize(size);
28340 this.monthPicker.child('table').setSize(size);
28342 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28343 this.updateMPMonth(this.mpSelMonth);
28344 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28345 this.updateMPYear(this.mpSelYear);
28347 this.monthPicker.slideIn('t', {duration:.2});
28350 updateMPYear : function(y){
28352 var ys = this.mpYears.elements;
28353 for(var i = 1; i <= 10; i++){
28354 var td = ys[i-1], y2;
28356 y2 = y + Math.round(i * .5);
28357 td.firstChild.innerHTML = y2;
28360 y2 = y - (5-Math.round(i * .5));
28361 td.firstChild.innerHTML = y2;
28364 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28368 updateMPMonth : function(sm){
28369 this.mpMonths.each(function(m, a, i){
28370 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28374 selectMPMonth: function(m){
28378 onMonthClick : function(e, t){
28380 var el = new Roo.Element(t), pn;
28381 if(el.is('button.x-date-mp-cancel')){
28382 this.hideMonthPicker();
28384 else if(el.is('button.x-date-mp-ok')){
28385 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28386 this.hideMonthPicker();
28388 else if(pn = el.up('td.x-date-mp-month', 2)){
28389 this.mpMonths.removeClass('x-date-mp-sel');
28390 pn.addClass('x-date-mp-sel');
28391 this.mpSelMonth = pn.dom.xmonth;
28393 else if(pn = el.up('td.x-date-mp-year', 2)){
28394 this.mpYears.removeClass('x-date-mp-sel');
28395 pn.addClass('x-date-mp-sel');
28396 this.mpSelYear = pn.dom.xyear;
28398 else if(el.is('a.x-date-mp-prev')){
28399 this.updateMPYear(this.mpyear-10);
28401 else if(el.is('a.x-date-mp-next')){
28402 this.updateMPYear(this.mpyear+10);
28406 onMonthDblClick : function(e, t){
28408 var el = new Roo.Element(t), pn;
28409 if(pn = el.up('td.x-date-mp-month', 2)){
28410 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28411 this.hideMonthPicker();
28413 else if(pn = el.up('td.x-date-mp-year', 2)){
28414 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28415 this.hideMonthPicker();
28419 hideMonthPicker : function(disableAnim){
28420 if(this.monthPicker){
28421 if(disableAnim === true){
28422 this.monthPicker.hide();
28424 this.monthPicker.slideOut('t', {duration:.2});
28430 showPrevMonth : function(e){
28431 this.update(this.activeDate.add("mo", -1));
28435 showNextMonth : function(e){
28436 this.update(this.activeDate.add("mo", 1));
28440 showPrevYear : function(){
28441 this.update(this.activeDate.add("y", -1));
28445 showNextYear : function(){
28446 this.update(this.activeDate.add("y", 1));
28450 handleMouseWheel : function(e){
28451 var delta = e.getWheelDelta();
28453 this.showPrevMonth();
28455 } else if(delta < 0){
28456 this.showNextMonth();
28462 handleDateClick : function(e, t){
28464 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28465 this.setValue(new Date(t.dateValue));
28466 this.fireEvent("select", this, this.value);
28471 selectToday : function(){
28472 this.setValue(new Date().clearTime());
28473 this.fireEvent("select", this, this.value);
28477 update : function(date)
28479 var vd = this.activeDate;
28480 this.activeDate = date;
28482 var t = date.getTime();
28483 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28484 this.cells.removeClass("x-date-selected");
28485 this.cells.each(function(c){
28486 if(c.dom.firstChild.dateValue == t){
28487 c.addClass("x-date-selected");
28488 setTimeout(function(){
28489 try{c.dom.firstChild.focus();}catch(e){}
28498 var days = date.getDaysInMonth();
28499 var firstOfMonth = date.getFirstDateOfMonth();
28500 var startingPos = firstOfMonth.getDay()-this.startDay;
28502 if(startingPos <= this.startDay){
28506 var pm = date.add("mo", -1);
28507 var prevStart = pm.getDaysInMonth()-startingPos;
28509 var cells = this.cells.elements;
28510 var textEls = this.textNodes;
28511 days += startingPos;
28513 // convert everything to numbers so it's fast
28514 var day = 86400000;
28515 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28516 var today = new Date().clearTime().getTime();
28517 var sel = date.clearTime().getTime();
28518 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28519 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28520 var ddMatch = this.disabledDatesRE;
28521 var ddText = this.disabledDatesText;
28522 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28523 var ddaysText = this.disabledDaysText;
28524 var format = this.format;
28526 var setCellClass = function(cal, cell){
28528 var t = d.getTime();
28529 cell.firstChild.dateValue = t;
28531 cell.className += " x-date-today";
28532 cell.title = cal.todayText;
28535 cell.className += " x-date-selected";
28536 setTimeout(function(){
28537 try{cell.firstChild.focus();}catch(e){}
28542 cell.className = " x-date-disabled";
28543 cell.title = cal.minText;
28547 cell.className = " x-date-disabled";
28548 cell.title = cal.maxText;
28552 if(ddays.indexOf(d.getDay()) != -1){
28553 cell.title = ddaysText;
28554 cell.className = " x-date-disabled";
28557 if(ddMatch && format){
28558 var fvalue = d.dateFormat(format);
28559 if(ddMatch.test(fvalue)){
28560 cell.title = ddText.replace("%0", fvalue);
28561 cell.className = " x-date-disabled";
28567 for(; i < startingPos; i++) {
28568 textEls[i].innerHTML = (++prevStart);
28569 d.setDate(d.getDate()+1);
28570 cells[i].className = "x-date-prevday";
28571 setCellClass(this, cells[i]);
28573 for(; i < days; i++){
28574 intDay = i - startingPos + 1;
28575 textEls[i].innerHTML = (intDay);
28576 d.setDate(d.getDate()+1);
28577 cells[i].className = "x-date-active";
28578 setCellClass(this, cells[i]);
28581 for(; i < 42; i++) {
28582 textEls[i].innerHTML = (++extraDays);
28583 d.setDate(d.getDate()+1);
28584 cells[i].className = "x-date-nextday";
28585 setCellClass(this, cells[i]);
28588 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28589 this.fireEvent('monthchange', this, date);
28591 if(!this.internalRender){
28592 var main = this.el.dom.firstChild;
28593 var w = main.offsetWidth;
28594 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28595 Roo.fly(main).setWidth(w);
28596 this.internalRender = true;
28597 // opera does not respect the auto grow header center column
28598 // then, after it gets a width opera refuses to recalculate
28599 // without a second pass
28600 if(Roo.isOpera && !this.secondPass){
28601 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28602 this.secondPass = true;
28603 this.update.defer(10, this, [date]);
28611 * Ext JS Library 1.1.1
28612 * Copyright(c) 2006-2007, Ext JS, LLC.
28614 * Originally Released Under LGPL - original licence link has changed is not relivant.
28617 * <script type="text/javascript">
28620 * @class Roo.TabPanel
28621 * @extends Roo.util.Observable
28622 * A lightweight tab container.
28626 // basic tabs 1, built from existing content
28627 var tabs = new Roo.TabPanel("tabs1");
28628 tabs.addTab("script", "View Script");
28629 tabs.addTab("markup", "View Markup");
28630 tabs.activate("script");
28632 // more advanced tabs, built from javascript
28633 var jtabs = new Roo.TabPanel("jtabs");
28634 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28636 // set up the UpdateManager
28637 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28638 var updater = tab2.getUpdateManager();
28639 updater.setDefaultUrl("ajax1.htm");
28640 tab2.on('activate', updater.refresh, updater, true);
28642 // Use setUrl for Ajax loading
28643 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28644 tab3.setUrl("ajax2.htm", null, true);
28647 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28650 jtabs.activate("jtabs-1");
28653 * Create a new TabPanel.
28654 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28655 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28657 Roo.TabPanel = function(container, config){
28659 * The container element for this TabPanel.
28660 * @type Roo.Element
28662 this.el = Roo.get(container, true);
28664 if(typeof config == "boolean"){
28665 this.tabPosition = config ? "bottom" : "top";
28667 Roo.apply(this, config);
28670 if(this.tabPosition == "bottom"){
28671 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28672 this.el.addClass("x-tabs-bottom");
28674 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28675 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28676 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28678 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28680 if(this.tabPosition != "bottom"){
28681 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28682 * @type Roo.Element
28684 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28685 this.el.addClass("x-tabs-top");
28689 this.bodyEl.setStyle("position", "relative");
28691 this.active = null;
28692 this.activateDelegate = this.activate.createDelegate(this);
28697 * Fires when the active tab changes
28698 * @param {Roo.TabPanel} this
28699 * @param {Roo.TabPanelItem} activePanel The new active tab
28703 * @event beforetabchange
28704 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28705 * @param {Roo.TabPanel} this
28706 * @param {Object} e Set cancel to true on this object to cancel the tab change
28707 * @param {Roo.TabPanelItem} tab The tab being changed to
28709 "beforetabchange" : true
28712 Roo.EventManager.onWindowResize(this.onResize, this);
28713 this.cpad = this.el.getPadding("lr");
28714 this.hiddenCount = 0;
28717 // toolbar on the tabbar support...
28718 if (this.toolbar) {
28719 var tcfg = this.toolbar;
28720 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28721 this.toolbar = new Roo.Toolbar(tcfg);
28722 if (Roo.isSafari) {
28723 var tbl = tcfg.container.child('table', true);
28724 tbl.setAttribute('width', '100%');
28731 Roo.TabPanel.superclass.constructor.call(this);
28734 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28736 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28738 tabPosition : "top",
28740 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28742 currentTabWidth : 0,
28744 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28748 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28752 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28754 preferredTabWidth : 175,
28756 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28758 resizeTabs : false,
28760 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28762 monitorResize : true,
28764 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28769 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28770 * @param {String} id The id of the div to use <b>or create</b>
28771 * @param {String} text The text for the tab
28772 * @param {String} content (optional) Content to put in the TabPanelItem body
28773 * @param {Boolean} closable (optional) True to create a close icon on the tab
28774 * @return {Roo.TabPanelItem} The created TabPanelItem
28776 addTab : function(id, text, content, closable){
28777 var item = new Roo.TabPanelItem(this, id, text, closable);
28778 this.addTabItem(item);
28780 item.setContent(content);
28786 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28787 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28788 * @return {Roo.TabPanelItem}
28790 getTab : function(id){
28791 return this.items[id];
28795 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28796 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28798 hideTab : function(id){
28799 var t = this.items[id];
28802 this.hiddenCount++;
28803 this.autoSizeTabs();
28808 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28809 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28811 unhideTab : function(id){
28812 var t = this.items[id];
28814 t.setHidden(false);
28815 this.hiddenCount--;
28816 this.autoSizeTabs();
28821 * Adds an existing {@link Roo.TabPanelItem}.
28822 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28824 addTabItem : function(item){
28825 this.items[item.id] = item;
28826 this.items.push(item);
28827 if(this.resizeTabs){
28828 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28829 this.autoSizeTabs();
28836 * Removes a {@link Roo.TabPanelItem}.
28837 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28839 removeTab : function(id){
28840 var items = this.items;
28841 var tab = items[id];
28842 if(!tab) { return; }
28843 var index = items.indexOf(tab);
28844 if(this.active == tab && items.length > 1){
28845 var newTab = this.getNextAvailable(index);
28850 this.stripEl.dom.removeChild(tab.pnode.dom);
28851 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28852 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28854 items.splice(index, 1);
28855 delete this.items[tab.id];
28856 tab.fireEvent("close", tab);
28857 tab.purgeListeners();
28858 this.autoSizeTabs();
28861 getNextAvailable : function(start){
28862 var items = this.items;
28864 // look for a next tab that will slide over to
28865 // replace the one being removed
28866 while(index < items.length){
28867 var item = items[++index];
28868 if(item && !item.isHidden()){
28872 // if one isn't found select the previous tab (on the left)
28875 var item = items[--index];
28876 if(item && !item.isHidden()){
28884 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28885 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28887 disableTab : function(id){
28888 var tab = this.items[id];
28889 if(tab && this.active != tab){
28895 * Enables a {@link Roo.TabPanelItem} that is disabled.
28896 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28898 enableTab : function(id){
28899 var tab = this.items[id];
28904 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28905 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28906 * @return {Roo.TabPanelItem} The TabPanelItem.
28908 activate : function(id){
28909 var tab = this.items[id];
28913 if(tab == this.active || tab.disabled){
28917 this.fireEvent("beforetabchange", this, e, tab);
28918 if(e.cancel !== true && !tab.disabled){
28920 this.active.hide();
28922 this.active = this.items[id];
28923 this.active.show();
28924 this.fireEvent("tabchange", this, this.active);
28930 * Gets the active {@link Roo.TabPanelItem}.
28931 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28933 getActiveTab : function(){
28934 return this.active;
28938 * Updates the tab body element to fit the height of the container element
28939 * for overflow scrolling
28940 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28942 syncHeight : function(targetHeight){
28943 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28944 var bm = this.bodyEl.getMargins();
28945 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28946 this.bodyEl.setHeight(newHeight);
28950 onResize : function(){
28951 if(this.monitorResize){
28952 this.autoSizeTabs();
28957 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28959 beginUpdate : function(){
28960 this.updating = true;
28964 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28966 endUpdate : function(){
28967 this.updating = false;
28968 this.autoSizeTabs();
28972 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28974 autoSizeTabs : function(){
28975 var count = this.items.length;
28976 var vcount = count - this.hiddenCount;
28977 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28980 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28981 var availWidth = Math.floor(w / vcount);
28982 var b = this.stripBody;
28983 if(b.getWidth() > w){
28984 var tabs = this.items;
28985 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28986 if(availWidth < this.minTabWidth){
28987 /*if(!this.sleft){ // incomplete scrolling code
28988 this.createScrollButtons();
28991 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28994 if(this.currentTabWidth < this.preferredTabWidth){
28995 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
29001 * Returns the number of tabs in this TabPanel.
29004 getCount : function(){
29005 return this.items.length;
29009 * Resizes all the tabs to the passed width
29010 * @param {Number} The new width
29012 setTabWidth : function(width){
29013 this.currentTabWidth = width;
29014 for(var i = 0, len = this.items.length; i < len; i++) {
29015 if(!this.items[i].isHidden()) {
29016 this.items[i].setWidth(width);
29022 * Destroys this TabPanel
29023 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
29025 destroy : function(removeEl){
29026 Roo.EventManager.removeResizeListener(this.onResize, this);
29027 for(var i = 0, len = this.items.length; i < len; i++){
29028 this.items[i].purgeListeners();
29030 if(removeEl === true){
29031 this.el.update("");
29038 * @class Roo.TabPanelItem
29039 * @extends Roo.util.Observable
29040 * Represents an individual item (tab plus body) in a TabPanel.
29041 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
29042 * @param {String} id The id of this TabPanelItem
29043 * @param {String} text The text for the tab of this TabPanelItem
29044 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
29046 Roo.TabPanelItem = function(tabPanel, id, text, closable){
29048 * The {@link Roo.TabPanel} this TabPanelItem belongs to
29049 * @type Roo.TabPanel
29051 this.tabPanel = tabPanel;
29053 * The id for this TabPanelItem
29058 this.disabled = false;
29062 this.loaded = false;
29063 this.closable = closable;
29066 * The body element for this TabPanelItem.
29067 * @type Roo.Element
29069 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
29070 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
29071 this.bodyEl.setStyle("display", "block");
29072 this.bodyEl.setStyle("zoom", "1");
29075 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
29077 this.el = Roo.get(els.el, true);
29078 this.inner = Roo.get(els.inner, true);
29079 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
29080 this.pnode = Roo.get(els.el.parentNode, true);
29081 this.el.on("mousedown", this.onTabMouseDown, this);
29082 this.el.on("click", this.onTabClick, this);
29085 var c = Roo.get(els.close, true);
29086 c.dom.title = this.closeText;
29087 c.addClassOnOver("close-over");
29088 c.on("click", this.closeClick, this);
29094 * Fires when this tab becomes the active tab.
29095 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29096 * @param {Roo.TabPanelItem} this
29100 * @event beforeclose
29101 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
29102 * @param {Roo.TabPanelItem} this
29103 * @param {Object} e Set cancel to true on this object to cancel the close.
29105 "beforeclose": true,
29108 * Fires when this tab is closed.
29109 * @param {Roo.TabPanelItem} this
29113 * @event deactivate
29114 * Fires when this tab is no longer the active tab.
29115 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29116 * @param {Roo.TabPanelItem} this
29118 "deactivate" : true
29120 this.hidden = false;
29122 Roo.TabPanelItem.superclass.constructor.call(this);
29125 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
29126 purgeListeners : function(){
29127 Roo.util.Observable.prototype.purgeListeners.call(this);
29128 this.el.removeAllListeners();
29131 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
29134 this.pnode.addClass("on");
29137 this.tabPanel.stripWrap.repaint();
29139 this.fireEvent("activate", this.tabPanel, this);
29143 * Returns true if this tab is the active tab.
29144 * @return {Boolean}
29146 isActive : function(){
29147 return this.tabPanel.getActiveTab() == this;
29151 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29154 this.pnode.removeClass("on");
29156 this.fireEvent("deactivate", this.tabPanel, this);
29159 hideAction : function(){
29160 this.bodyEl.hide();
29161 this.bodyEl.setStyle("position", "absolute");
29162 this.bodyEl.setLeft("-20000px");
29163 this.bodyEl.setTop("-20000px");
29166 showAction : function(){
29167 this.bodyEl.setStyle("position", "relative");
29168 this.bodyEl.setTop("");
29169 this.bodyEl.setLeft("");
29170 this.bodyEl.show();
29174 * Set the tooltip for the tab.
29175 * @param {String} tooltip The tab's tooltip
29177 setTooltip : function(text){
29178 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29179 this.textEl.dom.qtip = text;
29180 this.textEl.dom.removeAttribute('title');
29182 this.textEl.dom.title = text;
29186 onTabClick : function(e){
29187 e.preventDefault();
29188 this.tabPanel.activate(this.id);
29191 onTabMouseDown : function(e){
29192 e.preventDefault();
29193 this.tabPanel.activate(this.id);
29196 getWidth : function(){
29197 return this.inner.getWidth();
29200 setWidth : function(width){
29201 var iwidth = width - this.pnode.getPadding("lr");
29202 this.inner.setWidth(iwidth);
29203 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29204 this.pnode.setWidth(width);
29208 * Show or hide the tab
29209 * @param {Boolean} hidden True to hide or false to show.
29211 setHidden : function(hidden){
29212 this.hidden = hidden;
29213 this.pnode.setStyle("display", hidden ? "none" : "");
29217 * Returns true if this tab is "hidden"
29218 * @return {Boolean}
29220 isHidden : function(){
29221 return this.hidden;
29225 * Returns the text for this tab
29228 getText : function(){
29232 autoSize : function(){
29233 //this.el.beginMeasure();
29234 this.textEl.setWidth(1);
29236 * #2804 [new] Tabs in Roojs
29237 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29239 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29240 //this.el.endMeasure();
29244 * Sets the text for the tab (Note: this also sets the tooltip text)
29245 * @param {String} text The tab's text and tooltip
29247 setText : function(text){
29249 this.textEl.update(text);
29250 this.setTooltip(text);
29251 if(!this.tabPanel.resizeTabs){
29256 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29258 activate : function(){
29259 this.tabPanel.activate(this.id);
29263 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29265 disable : function(){
29266 if(this.tabPanel.active != this){
29267 this.disabled = true;
29268 this.pnode.addClass("disabled");
29273 * Enables this TabPanelItem if it was previously disabled.
29275 enable : function(){
29276 this.disabled = false;
29277 this.pnode.removeClass("disabled");
29281 * Sets the content for this TabPanelItem.
29282 * @param {String} content The content
29283 * @param {Boolean} loadScripts true to look for and load scripts
29285 setContent : function(content, loadScripts){
29286 this.bodyEl.update(content, loadScripts);
29290 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29291 * @return {Roo.UpdateManager} The UpdateManager
29293 getUpdateManager : function(){
29294 return this.bodyEl.getUpdateManager();
29298 * Set a URL to be used to load the content for this TabPanelItem.
29299 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29300 * @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)
29301 * @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)
29302 * @return {Roo.UpdateManager} The UpdateManager
29304 setUrl : function(url, params, loadOnce){
29305 if(this.refreshDelegate){
29306 this.un('activate', this.refreshDelegate);
29308 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29309 this.on("activate", this.refreshDelegate);
29310 return this.bodyEl.getUpdateManager();
29314 _handleRefresh : function(url, params, loadOnce){
29315 if(!loadOnce || !this.loaded){
29316 var updater = this.bodyEl.getUpdateManager();
29317 updater.update(url, params, this._setLoaded.createDelegate(this));
29322 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29323 * Will fail silently if the setUrl method has not been called.
29324 * This does not activate the panel, just updates its content.
29326 refresh : function(){
29327 if(this.refreshDelegate){
29328 this.loaded = false;
29329 this.refreshDelegate();
29334 _setLoaded : function(){
29335 this.loaded = true;
29339 closeClick : function(e){
29342 this.fireEvent("beforeclose", this, o);
29343 if(o.cancel !== true){
29344 this.tabPanel.removeTab(this.id);
29348 * The text displayed in the tooltip for the close icon.
29351 closeText : "Close this tab"
29355 Roo.TabPanel.prototype.createStrip = function(container){
29356 var strip = document.createElement("div");
29357 strip.className = "x-tabs-wrap";
29358 container.appendChild(strip);
29362 Roo.TabPanel.prototype.createStripList = function(strip){
29363 // div wrapper for retard IE
29364 // returns the "tr" element.
29365 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29366 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29367 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29368 return strip.firstChild.firstChild.firstChild.firstChild;
29371 Roo.TabPanel.prototype.createBody = function(container){
29372 var body = document.createElement("div");
29373 Roo.id(body, "tab-body");
29374 Roo.fly(body).addClass("x-tabs-body");
29375 container.appendChild(body);
29379 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29380 var body = Roo.getDom(id);
29382 body = document.createElement("div");
29385 Roo.fly(body).addClass("x-tabs-item-body");
29386 bodyEl.insertBefore(body, bodyEl.firstChild);
29390 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29391 var td = document.createElement("td");
29392 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29393 //stripEl.appendChild(td);
29395 td.className = "x-tabs-closable";
29396 if(!this.closeTpl){
29397 this.closeTpl = new Roo.Template(
29398 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29399 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29400 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29403 var el = this.closeTpl.overwrite(td, {"text": text});
29404 var close = el.getElementsByTagName("div")[0];
29405 var inner = el.getElementsByTagName("em")[0];
29406 return {"el": el, "close": close, "inner": inner};
29409 this.tabTpl = new Roo.Template(
29410 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29411 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29414 var el = this.tabTpl.overwrite(td, {"text": text});
29415 var inner = el.getElementsByTagName("em")[0];
29416 return {"el": el, "inner": inner};
29420 * Ext JS Library 1.1.1
29421 * Copyright(c) 2006-2007, Ext JS, LLC.
29423 * Originally Released Under LGPL - original licence link has changed is not relivant.
29426 * <script type="text/javascript">
29430 * @class Roo.Button
29431 * @extends Roo.util.Observable
29432 * Simple Button class
29433 * @cfg {String} text The button text
29434 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29435 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29436 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29437 * @cfg {Object} scope The scope of the handler
29438 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29439 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29440 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29441 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29442 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29443 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29444 applies if enableToggle = true)
29445 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29446 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29447 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29449 * Create a new button
29450 * @param {Object} config The config object
29452 Roo.Button = function(renderTo, config)
29456 renderTo = config.renderTo || false;
29459 Roo.apply(this, config);
29463 * Fires when this button is clicked
29464 * @param {Button} this
29465 * @param {EventObject} e The click event
29470 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29471 * @param {Button} this
29472 * @param {Boolean} pressed
29477 * Fires when the mouse hovers over the button
29478 * @param {Button} this
29479 * @param {Event} e The event object
29481 'mouseover' : true,
29484 * Fires when the mouse exits the button
29485 * @param {Button} this
29486 * @param {Event} e The event object
29491 * Fires when the button is rendered
29492 * @param {Button} this
29497 this.menu = Roo.menu.MenuMgr.get(this.menu);
29499 // register listeners first!! - so render can be captured..
29500 Roo.util.Observable.call(this);
29502 this.render(renderTo);
29508 Roo.extend(Roo.Button, Roo.util.Observable, {
29514 * Read-only. True if this button is hidden
29519 * Read-only. True if this button is disabled
29524 * Read-only. True if this button is pressed (only if enableToggle = true)
29530 * @cfg {Number} tabIndex
29531 * The DOM tabIndex for this button (defaults to undefined)
29533 tabIndex : undefined,
29536 * @cfg {Boolean} enableToggle
29537 * True to enable pressed/not pressed toggling (defaults to false)
29539 enableToggle: false,
29541 * @cfg {Roo.menu.Menu} menu
29542 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29546 * @cfg {String} menuAlign
29547 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29549 menuAlign : "tl-bl?",
29552 * @cfg {String} iconCls
29553 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29555 iconCls : undefined,
29557 * @cfg {String} type
29558 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29563 menuClassTarget: 'tr',
29566 * @cfg {String} clickEvent
29567 * The type of event to map to the button's event handler (defaults to 'click')
29569 clickEvent : 'click',
29572 * @cfg {Boolean} handleMouseEvents
29573 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29575 handleMouseEvents : true,
29578 * @cfg {String} tooltipType
29579 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29581 tooltipType : 'qtip',
29584 * @cfg {String} cls
29585 * A CSS class to apply to the button's main element.
29589 * @cfg {Roo.Template} template (Optional)
29590 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29591 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29592 * require code modifications if required elements (e.g. a button) aren't present.
29596 render : function(renderTo){
29598 if(this.hideParent){
29599 this.parentEl = Roo.get(renderTo);
29601 if(!this.dhconfig){
29602 if(!this.template){
29603 if(!Roo.Button.buttonTemplate){
29604 // hideous table template
29605 Roo.Button.buttonTemplate = new Roo.Template(
29606 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29607 '<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>',
29608 "</tr></tbody></table>");
29610 this.template = Roo.Button.buttonTemplate;
29612 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29613 var btnEl = btn.child("button:first");
29614 btnEl.on('focus', this.onFocus, this);
29615 btnEl.on('blur', this.onBlur, this);
29617 btn.addClass(this.cls);
29620 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29623 btnEl.addClass(this.iconCls);
29625 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29628 if(this.tabIndex !== undefined){
29629 btnEl.dom.tabIndex = this.tabIndex;
29632 if(typeof this.tooltip == 'object'){
29633 Roo.QuickTips.tips(Roo.apply({
29637 btnEl.dom[this.tooltipType] = this.tooltip;
29641 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29645 this.el.dom.id = this.el.id = this.id;
29648 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29649 this.menu.on("show", this.onMenuShow, this);
29650 this.menu.on("hide", this.onMenuHide, this);
29652 btn.addClass("x-btn");
29653 if(Roo.isIE && !Roo.isIE7){
29654 this.autoWidth.defer(1, this);
29658 if(this.handleMouseEvents){
29659 btn.on("mouseover", this.onMouseOver, this);
29660 btn.on("mouseout", this.onMouseOut, this);
29661 btn.on("mousedown", this.onMouseDown, this);
29663 btn.on(this.clickEvent, this.onClick, this);
29664 //btn.on("mouseup", this.onMouseUp, this);
29671 Roo.ButtonToggleMgr.register(this);
29673 this.el.addClass("x-btn-pressed");
29676 var repeater = new Roo.util.ClickRepeater(btn,
29677 typeof this.repeat == "object" ? this.repeat : {}
29679 repeater.on("click", this.onClick, this);
29682 this.fireEvent('render', this);
29686 * Returns the button's underlying element
29687 * @return {Roo.Element} The element
29689 getEl : function(){
29694 * Destroys this Button and removes any listeners.
29696 destroy : function(){
29697 Roo.ButtonToggleMgr.unregister(this);
29698 this.el.removeAllListeners();
29699 this.purgeListeners();
29704 autoWidth : function(){
29706 this.el.setWidth("auto");
29707 if(Roo.isIE7 && Roo.isStrict){
29708 var ib = this.el.child('button');
29709 if(ib && ib.getWidth() > 20){
29711 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29716 this.el.beginMeasure();
29718 if(this.el.getWidth() < this.minWidth){
29719 this.el.setWidth(this.minWidth);
29722 this.el.endMeasure();
29729 * Assigns this button's click handler
29730 * @param {Function} handler The function to call when the button is clicked
29731 * @param {Object} scope (optional) Scope for the function passed in
29733 setHandler : function(handler, scope){
29734 this.handler = handler;
29735 this.scope = scope;
29739 * Sets this button's text
29740 * @param {String} text The button text
29742 setText : function(text){
29745 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29751 * Gets the text for this button
29752 * @return {String} The button text
29754 getText : function(){
29762 this.hidden = false;
29764 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29772 this.hidden = true;
29774 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29779 * Convenience function for boolean show/hide
29780 * @param {Boolean} visible True to show, false to hide
29782 setVisible: function(visible){
29791 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29792 * @param {Boolean} state (optional) Force a particular state
29794 toggle : function(state){
29795 state = state === undefined ? !this.pressed : state;
29796 if(state != this.pressed){
29798 this.el.addClass("x-btn-pressed");
29799 this.pressed = true;
29800 this.fireEvent("toggle", this, true);
29802 this.el.removeClass("x-btn-pressed");
29803 this.pressed = false;
29804 this.fireEvent("toggle", this, false);
29806 if(this.toggleHandler){
29807 this.toggleHandler.call(this.scope || this, this, state);
29815 focus : function(){
29816 this.el.child('button:first').focus();
29820 * Disable this button
29822 disable : function(){
29824 this.el.addClass("x-btn-disabled");
29826 this.disabled = true;
29830 * Enable this button
29832 enable : function(){
29834 this.el.removeClass("x-btn-disabled");
29836 this.disabled = false;
29840 * Convenience function for boolean enable/disable
29841 * @param {Boolean} enabled True to enable, false to disable
29843 setDisabled : function(v){
29844 this[v !== true ? "enable" : "disable"]();
29848 onClick : function(e)
29851 e.preventDefault();
29856 if(!this.disabled){
29857 if(this.enableToggle){
29860 if(this.menu && !this.menu.isVisible()){
29861 this.menu.show(this.el, this.menuAlign);
29863 this.fireEvent("click", this, e);
29865 this.el.removeClass("x-btn-over");
29866 this.handler.call(this.scope || this, this, e);
29871 onMouseOver : function(e){
29872 if(!this.disabled){
29873 this.el.addClass("x-btn-over");
29874 this.fireEvent('mouseover', this, e);
29878 onMouseOut : function(e){
29879 if(!e.within(this.el, true)){
29880 this.el.removeClass("x-btn-over");
29881 this.fireEvent('mouseout', this, e);
29885 onFocus : function(e){
29886 if(!this.disabled){
29887 this.el.addClass("x-btn-focus");
29891 onBlur : function(e){
29892 this.el.removeClass("x-btn-focus");
29895 onMouseDown : function(e){
29896 if(!this.disabled && e.button == 0){
29897 this.el.addClass("x-btn-click");
29898 Roo.get(document).on('mouseup', this.onMouseUp, this);
29902 onMouseUp : function(e){
29904 this.el.removeClass("x-btn-click");
29905 Roo.get(document).un('mouseup', this.onMouseUp, this);
29909 onMenuShow : function(e){
29910 this.el.addClass("x-btn-menu-active");
29913 onMenuHide : function(e){
29914 this.el.removeClass("x-btn-menu-active");
29918 // Private utility class used by Button
29919 Roo.ButtonToggleMgr = function(){
29922 function toggleGroup(btn, state){
29924 var g = groups[btn.toggleGroup];
29925 for(var i = 0, l = g.length; i < l; i++){
29927 g[i].toggle(false);
29934 register : function(btn){
29935 if(!btn.toggleGroup){
29938 var g = groups[btn.toggleGroup];
29940 g = groups[btn.toggleGroup] = [];
29943 btn.on("toggle", toggleGroup);
29946 unregister : function(btn){
29947 if(!btn.toggleGroup){
29950 var g = groups[btn.toggleGroup];
29953 btn.un("toggle", toggleGroup);
29959 * Ext JS Library 1.1.1
29960 * Copyright(c) 2006-2007, Ext JS, LLC.
29962 * Originally Released Under LGPL - original licence link has changed is not relivant.
29965 * <script type="text/javascript">
29969 * @class Roo.SplitButton
29970 * @extends Roo.Button
29971 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29972 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29973 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29974 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29975 * @cfg {String} arrowTooltip The title attribute of the arrow
29977 * Create a new menu button
29978 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29979 * @param {Object} config The config object
29981 Roo.SplitButton = function(renderTo, config){
29982 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29984 * @event arrowclick
29985 * Fires when this button's arrow is clicked
29986 * @param {SplitButton} this
29987 * @param {EventObject} e The click event
29989 this.addEvents({"arrowclick":true});
29992 Roo.extend(Roo.SplitButton, Roo.Button, {
29993 render : function(renderTo){
29994 // this is one sweet looking template!
29995 var tpl = new Roo.Template(
29996 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29997 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29998 '<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>',
29999 "</tbody></table></td><td>",
30000 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
30001 '<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>',
30002 "</tbody></table></td></tr></table>"
30004 var btn = tpl.append(renderTo, [this.text, this.type], true);
30005 var btnEl = btn.child("button");
30007 btn.addClass(this.cls);
30010 btnEl.setStyle('background-image', 'url(' +this.icon +')');
30013 btnEl.addClass(this.iconCls);
30015 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
30019 if(this.handleMouseEvents){
30020 btn.on("mouseover", this.onMouseOver, this);
30021 btn.on("mouseout", this.onMouseOut, this);
30022 btn.on("mousedown", this.onMouseDown, this);
30023 btn.on("mouseup", this.onMouseUp, this);
30025 btn.on(this.clickEvent, this.onClick, this);
30027 if(typeof this.tooltip == 'object'){
30028 Roo.QuickTips.tips(Roo.apply({
30032 btnEl.dom[this.tooltipType] = this.tooltip;
30035 if(this.arrowTooltip){
30036 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
30045 this.el.addClass("x-btn-pressed");
30047 if(Roo.isIE && !Roo.isIE7){
30048 this.autoWidth.defer(1, this);
30053 this.menu.on("show", this.onMenuShow, this);
30054 this.menu.on("hide", this.onMenuHide, this);
30056 this.fireEvent('render', this);
30060 autoWidth : function(){
30062 var tbl = this.el.child("table:first");
30063 var tbl2 = this.el.child("table:last");
30064 this.el.setWidth("auto");
30065 tbl.setWidth("auto");
30066 if(Roo.isIE7 && Roo.isStrict){
30067 var ib = this.el.child('button:first');
30068 if(ib && ib.getWidth() > 20){
30070 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30075 this.el.beginMeasure();
30077 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
30078 tbl.setWidth(this.minWidth-tbl2.getWidth());
30081 this.el.endMeasure();
30084 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
30088 * Sets this button's click handler
30089 * @param {Function} handler The function to call when the button is clicked
30090 * @param {Object} scope (optional) Scope for the function passed above
30092 setHandler : function(handler, scope){
30093 this.handler = handler;
30094 this.scope = scope;
30098 * Sets this button's arrow click handler
30099 * @param {Function} handler The function to call when the arrow is clicked
30100 * @param {Object} scope (optional) Scope for the function passed above
30102 setArrowHandler : function(handler, scope){
30103 this.arrowHandler = handler;
30104 this.scope = scope;
30110 focus : function(){
30112 this.el.child("button:first").focus();
30117 onClick : function(e){
30118 e.preventDefault();
30119 if(!this.disabled){
30120 if(e.getTarget(".x-btn-menu-arrow-wrap")){
30121 if(this.menu && !this.menu.isVisible()){
30122 this.menu.show(this.el, this.menuAlign);
30124 this.fireEvent("arrowclick", this, e);
30125 if(this.arrowHandler){
30126 this.arrowHandler.call(this.scope || this, this, e);
30129 this.fireEvent("click", this, e);
30131 this.handler.call(this.scope || this, this, e);
30137 onMouseDown : function(e){
30138 if(!this.disabled){
30139 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30143 onMouseUp : function(e){
30144 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30149 // backwards compat
30150 Roo.MenuButton = Roo.SplitButton;/*
30152 * Ext JS Library 1.1.1
30153 * Copyright(c) 2006-2007, Ext JS, LLC.
30155 * Originally Released Under LGPL - original licence link has changed is not relivant.
30158 * <script type="text/javascript">
30162 * @class Roo.Toolbar
30163 * @children Roo.Toolbar.Item Roo.form.Field
30164 * Basic Toolbar class.
30166 * Creates a new Toolbar
30167 * @param {Object} container The config object
30169 Roo.Toolbar = function(container, buttons, config)
30171 /// old consturctor format still supported..
30172 if(container instanceof Array){ // omit the container for later rendering
30173 buttons = container;
30177 if (typeof(container) == 'object' && container.xtype) {
30178 config = container;
30179 container = config.container;
30180 buttons = config.buttons || []; // not really - use items!!
30183 if (config && config.items) {
30184 xitems = config.items;
30185 delete config.items;
30187 Roo.apply(this, config);
30188 this.buttons = buttons;
30191 this.render(container);
30193 this.xitems = xitems;
30194 Roo.each(xitems, function(b) {
30200 Roo.Toolbar.prototype = {
30202 * @cfg {Array} items
30203 * array of button configs or elements to add (will be converted to a MixedCollection)
30207 * @cfg {String/HTMLElement/Element} container
30208 * The id or element that will contain the toolbar
30211 render : function(ct){
30212 this.el = Roo.get(ct);
30214 this.el.addClass(this.cls);
30216 // using a table allows for vertical alignment
30217 // 100% width is needed by Safari...
30218 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30219 this.tr = this.el.child("tr", true);
30221 this.items = new Roo.util.MixedCollection(false, function(o){
30222 return o.id || ("item" + (++autoId));
30225 this.add.apply(this, this.buttons);
30226 delete this.buttons;
30231 * Adds element(s) to the toolbar -- this function takes a variable number of
30232 * arguments of mixed type and adds them to the toolbar.
30233 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30235 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30236 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30237 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30238 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30239 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30240 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30241 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30242 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30243 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30245 * @param {Mixed} arg2
30246 * @param {Mixed} etc.
30249 var a = arguments, l = a.length;
30250 for(var i = 0; i < l; i++){
30255 _add : function(el) {
30258 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30261 if (el.applyTo){ // some kind of form field
30262 return this.addField(el);
30264 if (el.render){ // some kind of Toolbar.Item
30265 return this.addItem(el);
30267 if (typeof el == "string"){ // string
30268 if(el == "separator" || el == "-"){
30269 return this.addSeparator();
30272 return this.addSpacer();
30275 return this.addFill();
30277 return this.addText(el);
30280 if(el.tagName){ // element
30281 return this.addElement(el);
30283 if(typeof el == "object"){ // must be button config?
30284 return this.addButton(el);
30286 // and now what?!?!
30292 * Add an Xtype element
30293 * @param {Object} xtype Xtype Object
30294 * @return {Object} created Object
30296 addxtype : function(e){
30297 return this.add(e);
30301 * Returns the Element for this toolbar.
30302 * @return {Roo.Element}
30304 getEl : function(){
30310 * @return {Roo.Toolbar.Item} The separator item
30312 addSeparator : function(){
30313 return this.addItem(new Roo.Toolbar.Separator());
30317 * Adds a spacer element
30318 * @return {Roo.Toolbar.Spacer} The spacer item
30320 addSpacer : function(){
30321 return this.addItem(new Roo.Toolbar.Spacer());
30325 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30326 * @return {Roo.Toolbar.Fill} The fill item
30328 addFill : function(){
30329 return this.addItem(new Roo.Toolbar.Fill());
30333 * Adds any standard HTML element to the toolbar
30334 * @param {String/HTMLElement/Element} el The element or id of the element to add
30335 * @return {Roo.Toolbar.Item} The element's item
30337 addElement : function(el){
30338 return this.addItem(new Roo.Toolbar.Item(el));
30341 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30342 * @type Roo.util.MixedCollection
30347 * Adds any Toolbar.Item or subclass
30348 * @param {Roo.Toolbar.Item} item
30349 * @return {Roo.Toolbar.Item} The item
30351 addItem : function(item){
30352 var td = this.nextBlock();
30354 this.items.add(item);
30359 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30360 * @param {Object/Array} config A button config or array of configs
30361 * @return {Roo.Toolbar.Button/Array}
30363 addButton : function(config){
30364 if(config instanceof Array){
30366 for(var i = 0, len = config.length; i < len; i++) {
30367 buttons.push(this.addButton(config[i]));
30372 if(!(config instanceof Roo.Toolbar.Button)){
30374 new Roo.Toolbar.SplitButton(config) :
30375 new Roo.Toolbar.Button(config);
30377 var td = this.nextBlock();
30384 * Adds text to the toolbar
30385 * @param {String} text The text to add
30386 * @return {Roo.Toolbar.Item} The element's item
30388 addText : function(text){
30389 return this.addItem(new Roo.Toolbar.TextItem(text));
30393 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30394 * @param {Number} index The index where the item is to be inserted
30395 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30396 * @return {Roo.Toolbar.Button/Item}
30398 insertButton : function(index, item){
30399 if(item instanceof Array){
30401 for(var i = 0, len = item.length; i < len; i++) {
30402 buttons.push(this.insertButton(index + i, item[i]));
30406 if (!(item instanceof Roo.Toolbar.Button)){
30407 item = new Roo.Toolbar.Button(item);
30409 var td = document.createElement("td");
30410 this.tr.insertBefore(td, this.tr.childNodes[index]);
30412 this.items.insert(index, item);
30417 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30418 * @param {Object} config
30419 * @return {Roo.Toolbar.Item} The element's item
30421 addDom : function(config, returnEl){
30422 var td = this.nextBlock();
30423 Roo.DomHelper.overwrite(td, config);
30424 var ti = new Roo.Toolbar.Item(td.firstChild);
30426 this.items.add(ti);
30431 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30432 * @type Roo.util.MixedCollection
30437 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30438 * Note: the field should not have been rendered yet. For a field that has already been
30439 * rendered, use {@link #addElement}.
30440 * @param {Roo.form.Field} field
30441 * @return {Roo.ToolbarItem}
30445 addField : function(field) {
30446 if (!this.fields) {
30448 this.fields = new Roo.util.MixedCollection(false, function(o){
30449 return o.id || ("item" + (++autoId));
30454 var td = this.nextBlock();
30456 var ti = new Roo.Toolbar.Item(td.firstChild);
30458 this.items.add(ti);
30459 this.fields.add(field);
30470 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30471 this.el.child('div').hide();
30479 this.el.child('div').show();
30483 nextBlock : function(){
30484 var td = document.createElement("td");
30485 this.tr.appendChild(td);
30490 destroy : function(){
30491 if(this.items){ // rendered?
30492 Roo.destroy.apply(Roo, this.items.items);
30494 if(this.fields){ // rendered?
30495 Roo.destroy.apply(Roo, this.fields.items);
30497 Roo.Element.uncache(this.el, this.tr);
30502 * @class Roo.Toolbar.Item
30503 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30505 * Creates a new Item
30506 * @param {HTMLElement} el
30508 Roo.Toolbar.Item = function(el){
30510 if (typeof (el.xtype) != 'undefined') {
30515 this.el = Roo.getDom(el);
30516 this.id = Roo.id(this.el);
30517 this.hidden = false;
30522 * Fires when the button is rendered
30523 * @param {Button} this
30527 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30529 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30530 //Roo.Toolbar.Item.prototype = {
30533 * Get this item's HTML Element
30534 * @return {HTMLElement}
30536 getEl : function(){
30541 render : function(td){
30544 td.appendChild(this.el);
30546 this.fireEvent('render', this);
30550 * Removes and destroys this item.
30552 destroy : function(){
30553 this.td.parentNode.removeChild(this.td);
30560 this.hidden = false;
30561 this.td.style.display = "";
30568 this.hidden = true;
30569 this.td.style.display = "none";
30573 * Convenience function for boolean show/hide.
30574 * @param {Boolean} visible true to show/false to hide
30576 setVisible: function(visible){
30585 * Try to focus this item.
30587 focus : function(){
30588 Roo.fly(this.el).focus();
30592 * Disables this item.
30594 disable : function(){
30595 Roo.fly(this.td).addClass("x-item-disabled");
30596 this.disabled = true;
30597 this.el.disabled = true;
30601 * Enables this item.
30603 enable : function(){
30604 Roo.fly(this.td).removeClass("x-item-disabled");
30605 this.disabled = false;
30606 this.el.disabled = false;
30612 * @class Roo.Toolbar.Separator
30613 * @extends Roo.Toolbar.Item
30614 * A simple toolbar separator class
30616 * Creates a new Separator
30618 Roo.Toolbar.Separator = function(cfg){
30620 var s = document.createElement("span");
30621 s.className = "ytb-sep";
30626 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30628 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30629 enable:Roo.emptyFn,
30630 disable:Roo.emptyFn,
30635 * @class Roo.Toolbar.Spacer
30636 * @extends Roo.Toolbar.Item
30637 * A simple element that adds extra horizontal space to a toolbar.
30639 * Creates a new Spacer
30641 Roo.Toolbar.Spacer = function(cfg){
30642 var s = document.createElement("div");
30643 s.className = "ytb-spacer";
30647 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30649 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30650 enable:Roo.emptyFn,
30651 disable:Roo.emptyFn,
30656 * @class Roo.Toolbar.Fill
30657 * @extends Roo.Toolbar.Spacer
30658 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30660 * Creates a new Spacer
30662 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30664 render : function(td){
30665 td.style.width = '100%';
30666 Roo.Toolbar.Fill.superclass.render.call(this, td);
30671 * @class Roo.Toolbar.TextItem
30672 * @extends Roo.Toolbar.Item
30673 * A simple class that renders text directly into a toolbar.
30675 * Creates a new TextItem
30676 * @cfg {string} text
30678 Roo.Toolbar.TextItem = function(cfg){
30679 var text = cfg || "";
30680 if (typeof(cfg) == 'object') {
30681 text = cfg.text || "";
30685 var s = document.createElement("span");
30686 s.className = "ytb-text";
30687 s.innerHTML = text;
30692 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30694 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30697 enable:Roo.emptyFn,
30698 disable:Roo.emptyFn,
30703 * @class Roo.Toolbar.Button
30704 * @extends Roo.Button
30705 * A button that renders into a toolbar.
30707 * Creates a new Button
30708 * @param {Object} config A standard {@link Roo.Button} config object
30710 Roo.Toolbar.Button = function(config){
30711 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30713 Roo.extend(Roo.Toolbar.Button, Roo.Button,
30717 render : function(td){
30719 Roo.Toolbar.Button.superclass.render.call(this, td);
30723 * Removes and destroys this button
30725 destroy : function(){
30726 Roo.Toolbar.Button.superclass.destroy.call(this);
30727 this.td.parentNode.removeChild(this.td);
30731 * Shows this button
30734 this.hidden = false;
30735 this.td.style.display = "";
30739 * Hides this button
30742 this.hidden = true;
30743 this.td.style.display = "none";
30747 * Disables this item
30749 disable : function(){
30750 Roo.fly(this.td).addClass("x-item-disabled");
30751 this.disabled = true;
30755 * Enables this item
30757 enable : function(){
30758 Roo.fly(this.td).removeClass("x-item-disabled");
30759 this.disabled = false;
30762 // backwards compat
30763 Roo.ToolbarButton = Roo.Toolbar.Button;
30766 * @class Roo.Toolbar.SplitButton
30767 * @extends Roo.SplitButton
30768 * A menu button that renders into a toolbar.
30770 * Creates a new SplitButton
30771 * @param {Object} config A standard {@link Roo.SplitButton} config object
30773 Roo.Toolbar.SplitButton = function(config){
30774 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30776 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30777 render : function(td){
30779 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30783 * Removes and destroys this button
30785 destroy : function(){
30786 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30787 this.td.parentNode.removeChild(this.td);
30791 * Shows this button
30794 this.hidden = false;
30795 this.td.style.display = "";
30799 * Hides this button
30802 this.hidden = true;
30803 this.td.style.display = "none";
30807 // backwards compat
30808 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30810 * Ext JS Library 1.1.1
30811 * Copyright(c) 2006-2007, Ext JS, LLC.
30813 * Originally Released Under LGPL - original licence link has changed is not relivant.
30816 * <script type="text/javascript">
30820 * @class Roo.PagingToolbar
30821 * @extends Roo.Toolbar
30822 * @children Roo.Toolbar.Item Roo.form.Field
30823 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30825 * Create a new PagingToolbar
30826 * @param {Object} config The config object
30828 Roo.PagingToolbar = function(el, ds, config)
30830 // old args format still supported... - xtype is prefered..
30831 if (typeof(el) == 'object' && el.xtype) {
30832 // created from xtype...
30834 ds = el.dataSource;
30835 el = config.container;
30838 if (config.items) {
30839 items = config.items;
30843 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30846 this.renderButtons(this.el);
30849 // supprot items array.
30851 Roo.each(items, function(e) {
30852 this.add(Roo.factory(e));
30857 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30860 * @cfg {String/HTMLElement/Element} container
30861 * container The id or element that will contain the toolbar
30864 * @cfg {Boolean} displayInfo
30865 * True to display the displayMsg (defaults to false)
30870 * @cfg {Number} pageSize
30871 * The number of records to display per page (defaults to 20)
30875 * @cfg {String} displayMsg
30876 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30878 displayMsg : 'Displaying {0} - {1} of {2}',
30880 * @cfg {String} emptyMsg
30881 * The message to display when no records are found (defaults to "No data to display")
30883 emptyMsg : 'No data to display',
30885 * Customizable piece of the default paging text (defaults to "Page")
30888 beforePageText : "Page",
30890 * Customizable piece of the default paging text (defaults to "of %0")
30893 afterPageText : "of {0}",
30895 * Customizable piece of the default paging text (defaults to "First Page")
30898 firstText : "First Page",
30900 * Customizable piece of the default paging text (defaults to "Previous Page")
30903 prevText : "Previous Page",
30905 * Customizable piece of the default paging text (defaults to "Next Page")
30908 nextText : "Next Page",
30910 * Customizable piece of the default paging text (defaults to "Last Page")
30913 lastText : "Last Page",
30915 * Customizable piece of the default paging text (defaults to "Refresh")
30918 refreshText : "Refresh",
30921 renderButtons : function(el){
30922 Roo.PagingToolbar.superclass.render.call(this, el);
30923 this.first = this.addButton({
30924 tooltip: this.firstText,
30925 cls: "x-btn-icon x-grid-page-first",
30927 handler: this.onClick.createDelegate(this, ["first"])
30929 this.prev = this.addButton({
30930 tooltip: this.prevText,
30931 cls: "x-btn-icon x-grid-page-prev",
30933 handler: this.onClick.createDelegate(this, ["prev"])
30935 //this.addSeparator();
30936 this.add(this.beforePageText);
30937 this.field = Roo.get(this.addDom({
30942 cls: "x-grid-page-number"
30944 this.field.on("keydown", this.onPagingKeydown, this);
30945 this.field.on("focus", function(){this.dom.select();});
30946 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30947 this.field.setHeight(18);
30948 //this.addSeparator();
30949 this.next = this.addButton({
30950 tooltip: this.nextText,
30951 cls: "x-btn-icon x-grid-page-next",
30953 handler: this.onClick.createDelegate(this, ["next"])
30955 this.last = this.addButton({
30956 tooltip: this.lastText,
30957 cls: "x-btn-icon x-grid-page-last",
30959 handler: this.onClick.createDelegate(this, ["last"])
30961 //this.addSeparator();
30962 this.loading = this.addButton({
30963 tooltip: this.refreshText,
30964 cls: "x-btn-icon x-grid-loading",
30965 handler: this.onClick.createDelegate(this, ["refresh"])
30968 if(this.displayInfo){
30969 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30974 updateInfo : function(){
30975 if(this.displayEl){
30976 var count = this.ds.getCount();
30977 var msg = count == 0 ?
30981 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30983 this.displayEl.update(msg);
30988 onLoad : function(ds, r, o){
30989 this.cursor = o.params ? o.params.start : 0;
30990 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30992 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30993 this.field.dom.value = ap;
30994 this.first.setDisabled(ap == 1);
30995 this.prev.setDisabled(ap == 1);
30996 this.next.setDisabled(ap == ps);
30997 this.last.setDisabled(ap == ps);
30998 this.loading.enable();
31003 getPageData : function(){
31004 var total = this.ds.getTotalCount();
31007 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
31008 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
31013 onLoadError : function(){
31014 this.loading.enable();
31018 onPagingKeydown : function(e){
31019 var k = e.getKey();
31020 var d = this.getPageData();
31022 var v = this.field.dom.value, pageNum;
31023 if(!v || isNaN(pageNum = parseInt(v, 10))){
31024 this.field.dom.value = d.activePage;
31027 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
31028 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31031 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))
31033 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
31034 this.field.dom.value = pageNum;
31035 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
31038 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
31040 var v = this.field.dom.value, pageNum;
31041 var increment = (e.shiftKey) ? 10 : 1;
31042 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
31045 if(!v || isNaN(pageNum = parseInt(v, 10))) {
31046 this.field.dom.value = d.activePage;
31049 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
31051 this.field.dom.value = parseInt(v, 10) + increment;
31052 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
31053 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31060 beforeLoad : function(){
31062 this.loading.disable();
31067 onClick : function(which){
31071 ds.load({params:{start: 0, limit: this.pageSize}});
31074 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
31077 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
31080 var total = ds.getTotalCount();
31081 var extra = total % this.pageSize;
31082 var lastStart = extra ? (total - extra) : total-this.pageSize;
31083 ds.load({params:{start: lastStart, limit: this.pageSize}});
31086 ds.load({params:{start: this.cursor, limit: this.pageSize}});
31092 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
31093 * @param {Roo.data.Store} store The data store to unbind
31095 unbind : function(ds){
31096 ds.un("beforeload", this.beforeLoad, this);
31097 ds.un("load", this.onLoad, this);
31098 ds.un("loadexception", this.onLoadError, this);
31099 ds.un("remove", this.updateInfo, this);
31100 ds.un("add", this.updateInfo, this);
31101 this.ds = undefined;
31105 * Binds the paging toolbar to the specified {@link Roo.data.Store}
31106 * @param {Roo.data.Store} store The data store to bind
31108 bind : function(ds){
31109 ds.on("beforeload", this.beforeLoad, this);
31110 ds.on("load", this.onLoad, this);
31111 ds.on("loadexception", this.onLoadError, this);
31112 ds.on("remove", this.updateInfo, this);
31113 ds.on("add", this.updateInfo, this);
31118 * Ext JS Library 1.1.1
31119 * Copyright(c) 2006-2007, Ext JS, LLC.
31121 * Originally Released Under LGPL - original licence link has changed is not relivant.
31124 * <script type="text/javascript">
31128 * @class Roo.Resizable
31129 * @extends Roo.util.Observable
31130 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
31131 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
31132 * 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
31133 * the element will be wrapped for you automatically.</p>
31134 * <p>Here is the list of valid resize handles:</p>
31137 ------ -------------------
31146 'hd' horizontal drag
31149 * <p>Here's an example showing the creation of a typical Resizable:</p>
31151 var resizer = new Roo.Resizable("element-id", {
31159 resizer.on("resize", myHandler);
31161 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31162 * resizer.east.setDisplayed(false);</p>
31163 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31164 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31165 * resize operation's new size (defaults to [0, 0])
31166 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31167 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31168 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31169 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31170 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31171 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31172 * @cfg {Number} width The width of the element in pixels (defaults to null)
31173 * @cfg {Number} height The height of the element in pixels (defaults to null)
31174 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31175 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31176 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31177 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31178 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31179 * in favor of the handles config option (defaults to false)
31180 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31181 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31182 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31183 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31184 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31185 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31186 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31187 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31188 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31189 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31190 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31192 * Create a new resizable component
31193 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31194 * @param {Object} config configuration options
31196 Roo.Resizable = function(el, config)
31198 this.el = Roo.get(el);
31200 if(config && config.wrap){
31201 config.resizeChild = this.el;
31202 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31203 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31204 this.el.setStyle("overflow", "hidden");
31205 this.el.setPositioning(config.resizeChild.getPositioning());
31206 config.resizeChild.clearPositioning();
31207 if(!config.width || !config.height){
31208 var csize = config.resizeChild.getSize();
31209 this.el.setSize(csize.width, csize.height);
31211 if(config.pinned && !config.adjustments){
31212 config.adjustments = "auto";
31216 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31217 this.proxy.unselectable();
31218 this.proxy.enableDisplayMode('block');
31220 Roo.apply(this, config);
31223 this.disableTrackOver = true;
31224 this.el.addClass("x-resizable-pinned");
31226 // if the element isn't positioned, make it relative
31227 var position = this.el.getStyle("position");
31228 if(position != "absolute" && position != "fixed"){
31229 this.el.setStyle("position", "relative");
31231 if(!this.handles){ // no handles passed, must be legacy style
31232 this.handles = 's,e,se';
31233 if(this.multiDirectional){
31234 this.handles += ',n,w';
31237 if(this.handles == "all"){
31238 this.handles = "n s e w ne nw se sw";
31240 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31241 var ps = Roo.Resizable.positions;
31242 for(var i = 0, len = hs.length; i < len; i++){
31243 if(hs[i] && ps[hs[i]]){
31244 var pos = ps[hs[i]];
31245 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31249 this.corner = this.southeast;
31251 // updateBox = the box can move..
31252 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31253 this.updateBox = true;
31256 this.activeHandle = null;
31258 if(this.resizeChild){
31259 if(typeof this.resizeChild == "boolean"){
31260 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31262 this.resizeChild = Roo.get(this.resizeChild, true);
31266 if(this.adjustments == "auto"){
31267 var rc = this.resizeChild;
31268 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31269 if(rc && (hw || hn)){
31270 rc.position("relative");
31271 rc.setLeft(hw ? hw.el.getWidth() : 0);
31272 rc.setTop(hn ? hn.el.getHeight() : 0);
31274 this.adjustments = [
31275 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31276 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31280 if(this.draggable){
31281 this.dd = this.dynamic ?
31282 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31283 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31289 * @event beforeresize
31290 * Fired before resize is allowed. Set enabled to false to cancel resize.
31291 * @param {Roo.Resizable} this
31292 * @param {Roo.EventObject} e The mousedown event
31294 "beforeresize" : true,
31297 * Fired a resizing.
31298 * @param {Roo.Resizable} this
31299 * @param {Number} x The new x position
31300 * @param {Number} y The new y position
31301 * @param {Number} w The new w width
31302 * @param {Number} h The new h hight
31303 * @param {Roo.EventObject} e The mouseup event
31308 * Fired after a resize.
31309 * @param {Roo.Resizable} this
31310 * @param {Number} width The new width
31311 * @param {Number} height The new height
31312 * @param {Roo.EventObject} e The mouseup event
31317 if(this.width !== null && this.height !== null){
31318 this.resizeTo(this.width, this.height);
31320 this.updateChildSize();
31323 this.el.dom.style.zoom = 1;
31325 Roo.Resizable.superclass.constructor.call(this);
31328 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31329 resizeChild : false,
31330 adjustments : [0, 0],
31340 multiDirectional : false,
31341 disableTrackOver : false,
31342 easing : 'easeOutStrong',
31343 widthIncrement : 0,
31344 heightIncrement : 0,
31348 preserveRatio : false,
31349 transparent: false,
31355 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31357 constrainTo: undefined,
31359 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31361 resizeRegion: undefined,
31365 * Perform a manual resize
31366 * @param {Number} width
31367 * @param {Number} height
31369 resizeTo : function(width, height){
31370 this.el.setSize(width, height);
31371 this.updateChildSize();
31372 this.fireEvent("resize", this, width, height, null);
31376 startSizing : function(e, handle){
31377 this.fireEvent("beforeresize", this, e);
31378 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31381 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31382 this.overlay.unselectable();
31383 this.overlay.enableDisplayMode("block");
31384 this.overlay.on("mousemove", this.onMouseMove, this);
31385 this.overlay.on("mouseup", this.onMouseUp, this);
31387 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31389 this.resizing = true;
31390 this.startBox = this.el.getBox();
31391 this.startPoint = e.getXY();
31392 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31393 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31395 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31396 this.overlay.show();
31398 if(this.constrainTo) {
31399 var ct = Roo.get(this.constrainTo);
31400 this.resizeRegion = ct.getRegion().adjust(
31401 ct.getFrameWidth('t'),
31402 ct.getFrameWidth('l'),
31403 -ct.getFrameWidth('b'),
31404 -ct.getFrameWidth('r')
31408 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31410 this.proxy.setBox(this.startBox);
31412 this.proxy.setStyle('visibility', 'visible');
31418 onMouseDown : function(handle, e){
31421 this.activeHandle = handle;
31422 this.startSizing(e, handle);
31427 onMouseUp : function(e){
31428 var size = this.resizeElement();
31429 this.resizing = false;
31431 this.overlay.hide();
31433 this.fireEvent("resize", this, size.width, size.height, e);
31437 updateChildSize : function(){
31439 if(this.resizeChild){
31441 var child = this.resizeChild;
31442 var adj = this.adjustments;
31443 if(el.dom.offsetWidth){
31444 var b = el.getSize(true);
31445 child.setSize(b.width+adj[0], b.height+adj[1]);
31447 // Second call here for IE
31448 // The first call enables instant resizing and
31449 // the second call corrects scroll bars if they
31452 setTimeout(function(){
31453 if(el.dom.offsetWidth){
31454 var b = el.getSize(true);
31455 child.setSize(b.width+adj[0], b.height+adj[1]);
31463 snap : function(value, inc, min){
31464 if(!inc || !value) {
31467 var newValue = value;
31468 var m = value % inc;
31471 newValue = value + (inc-m);
31473 newValue = value - m;
31476 return Math.max(min, newValue);
31480 resizeElement : function(){
31481 var box = this.proxy.getBox();
31482 if(this.updateBox){
31483 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31485 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31487 this.updateChildSize();
31495 constrain : function(v, diff, m, mx){
31498 }else if(v - diff > mx){
31505 onMouseMove : function(e){
31508 try{// try catch so if something goes wrong the user doesn't get hung
31510 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31514 //var curXY = this.startPoint;
31515 var curSize = this.curSize || this.startBox;
31516 var x = this.startBox.x, y = this.startBox.y;
31517 var ox = x, oy = y;
31518 var w = curSize.width, h = curSize.height;
31519 var ow = w, oh = h;
31520 var mw = this.minWidth, mh = this.minHeight;
31521 var mxw = this.maxWidth, mxh = this.maxHeight;
31522 var wi = this.widthIncrement;
31523 var hi = this.heightIncrement;
31525 var eventXY = e.getXY();
31526 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31527 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31529 var pos = this.activeHandle.position;
31534 w = Math.min(Math.max(mw, w), mxw);
31539 h = Math.min(Math.max(mh, h), mxh);
31544 w = Math.min(Math.max(mw, w), mxw);
31545 h = Math.min(Math.max(mh, h), mxh);
31548 diffY = this.constrain(h, diffY, mh, mxh);
31555 var adiffX = Math.abs(diffX);
31556 var sub = (adiffX % wi); // how much
31557 if (sub > (wi/2)) { // far enough to snap
31558 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31560 // remove difference..
31561 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31565 x = Math.max(this.minX, x);
31568 diffX = this.constrain(w, diffX, mw, mxw);
31574 w = Math.min(Math.max(mw, w), mxw);
31575 diffY = this.constrain(h, diffY, mh, mxh);
31580 diffX = this.constrain(w, diffX, mw, mxw);
31581 diffY = this.constrain(h, diffY, mh, mxh);
31588 diffX = this.constrain(w, diffX, mw, mxw);
31590 h = Math.min(Math.max(mh, h), mxh);
31596 var sw = this.snap(w, wi, mw);
31597 var sh = this.snap(h, hi, mh);
31598 if(sw != w || sh != h){
31621 if(this.preserveRatio){
31626 h = Math.min(Math.max(mh, h), mxh);
31631 w = Math.min(Math.max(mw, w), mxw);
31636 w = Math.min(Math.max(mw, w), mxw);
31642 w = Math.min(Math.max(mw, w), mxw);
31648 h = Math.min(Math.max(mh, h), mxh);
31656 h = Math.min(Math.max(mh, h), mxh);
31666 h = Math.min(Math.max(mh, h), mxh);
31674 if (pos == 'hdrag') {
31677 this.proxy.setBounds(x, y, w, h);
31679 this.resizeElement();
31683 this.fireEvent("resizing", this, x, y, w, h, e);
31687 handleOver : function(){
31689 this.el.addClass("x-resizable-over");
31694 handleOut : function(){
31695 if(!this.resizing){
31696 this.el.removeClass("x-resizable-over");
31701 * Returns the element this component is bound to.
31702 * @return {Roo.Element}
31704 getEl : function(){
31709 * Returns the resizeChild element (or null).
31710 * @return {Roo.Element}
31712 getResizeChild : function(){
31713 return this.resizeChild;
31715 groupHandler : function()
31720 * Destroys this resizable. If the element was wrapped and
31721 * removeEl is not true then the element remains.
31722 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31724 destroy : function(removeEl){
31725 this.proxy.remove();
31727 this.overlay.removeAllListeners();
31728 this.overlay.remove();
31730 var ps = Roo.Resizable.positions;
31732 if(typeof ps[k] != "function" && this[ps[k]]){
31733 var h = this[ps[k]];
31734 h.el.removeAllListeners();
31739 this.el.update("");
31746 // hash to map config positions to true positions
31747 Roo.Resizable.positions = {
31748 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31753 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31755 // only initialize the template if resizable is used
31756 var tpl = Roo.DomHelper.createTemplate(
31757 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31760 Roo.Resizable.Handle.prototype.tpl = tpl;
31762 this.position = pos;
31764 // show north drag fro topdra
31765 var handlepos = pos == 'hdrag' ? 'north' : pos;
31767 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31768 if (pos == 'hdrag') {
31769 this.el.setStyle('cursor', 'pointer');
31771 this.el.unselectable();
31773 this.el.setOpacity(0);
31775 this.el.on("mousedown", this.onMouseDown, this);
31776 if(!disableTrackOver){
31777 this.el.on("mouseover", this.onMouseOver, this);
31778 this.el.on("mouseout", this.onMouseOut, this);
31783 Roo.Resizable.Handle.prototype = {
31784 afterResize : function(rz){
31789 onMouseDown : function(e){
31790 this.rz.onMouseDown(this, e);
31793 onMouseOver : function(e){
31794 this.rz.handleOver(this, e);
31797 onMouseOut : function(e){
31798 this.rz.handleOut(this, e);
31802 * Ext JS Library 1.1.1
31803 * Copyright(c) 2006-2007, Ext JS, LLC.
31805 * Originally Released Under LGPL - original licence link has changed is not relivant.
31808 * <script type="text/javascript">
31812 * @class Roo.Editor
31813 * @extends Roo.Component
31814 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31816 * Create a new Editor
31817 * @param {Roo.form.Field} field The Field object (or descendant)
31818 * @param {Object} config The config object
31820 Roo.Editor = function(field, config){
31821 Roo.Editor.superclass.constructor.call(this, config);
31822 this.field = field;
31825 * @event beforestartedit
31826 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31827 * false from the handler of this event.
31828 * @param {Editor} this
31829 * @param {Roo.Element} boundEl The underlying element bound to this editor
31830 * @param {Mixed} value The field value being set
31832 "beforestartedit" : true,
31835 * Fires when this editor is displayed
31836 * @param {Roo.Element} boundEl The underlying element bound to this editor
31837 * @param {Mixed} value The starting field value
31839 "startedit" : true,
31841 * @event beforecomplete
31842 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31843 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31844 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31845 * event will not fire since no edit actually occurred.
31846 * @param {Editor} this
31847 * @param {Mixed} value The current field value
31848 * @param {Mixed} startValue The original field value
31850 "beforecomplete" : true,
31853 * Fires after editing is complete and any changed value has been written to the underlying field.
31854 * @param {Editor} this
31855 * @param {Mixed} value The current field value
31856 * @param {Mixed} startValue The original field value
31860 * @event specialkey
31861 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31862 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31863 * @param {Roo.form.Field} this
31864 * @param {Roo.EventObject} e The event object
31866 "specialkey" : true
31870 Roo.extend(Roo.Editor, Roo.Component, {
31872 * @cfg {Boolean/String} autosize
31873 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31874 * or "height" to adopt the height only (defaults to false)
31877 * @cfg {Boolean} revertInvalid
31878 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31879 * validation fails (defaults to true)
31882 * @cfg {Boolean} ignoreNoChange
31883 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31884 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31885 * will never be ignored.
31888 * @cfg {Boolean} hideEl
31889 * False to keep the bound element visible while the editor is displayed (defaults to true)
31892 * @cfg {Mixed} value
31893 * The data value of the underlying field (defaults to "")
31897 * @cfg {String} alignment
31898 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31902 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31903 * for bottom-right shadow (defaults to "frame")
31907 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31911 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31913 completeOnEnter : false,
31915 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31917 cancelOnEsc : false,
31919 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31924 onRender : function(ct, position){
31925 this.el = new Roo.Layer({
31926 shadow: this.shadow,
31932 constrain: this.constrain
31934 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31935 if(this.field.msgTarget != 'title'){
31936 this.field.msgTarget = 'qtip';
31938 this.field.render(this.el);
31940 this.field.el.dom.setAttribute('autocomplete', 'off');
31942 this.field.on("specialkey", this.onSpecialKey, this);
31943 if(this.swallowKeys){
31944 this.field.el.swallowEvent(['keydown','keypress']);
31947 this.field.on("blur", this.onBlur, this);
31948 if(this.field.grow){
31949 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31953 onSpecialKey : function(field, e)
31955 //Roo.log('editor onSpecialKey');
31956 if(this.completeOnEnter && e.getKey() == e.ENTER){
31958 this.completeEdit();
31961 // do not fire special key otherwise it might hide close the editor...
31962 if(e.getKey() == e.ENTER){
31965 if(this.cancelOnEsc && e.getKey() == e.ESC){
31969 this.fireEvent('specialkey', field, e);
31974 * Starts the editing process and shows the editor.
31975 * @param {String/HTMLElement/Element} el The element to edit
31976 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31977 * to the innerHTML of el.
31979 startEdit : function(el, value){
31981 this.completeEdit();
31983 this.boundEl = Roo.get(el);
31984 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31985 if(!this.rendered){
31986 this.render(this.parentEl || document.body);
31988 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31991 this.startValue = v;
31992 this.field.setValue(v);
31994 var sz = this.boundEl.getSize();
31995 switch(this.autoSize){
31997 this.setSize(sz.width, "");
32000 this.setSize("", sz.height);
32003 this.setSize(sz.width, sz.height);
32006 this.el.alignTo(this.boundEl, this.alignment);
32007 this.editing = true;
32009 Roo.QuickTips.disable();
32015 * Sets the height and width of this editor.
32016 * @param {Number} width The new width
32017 * @param {Number} height The new height
32019 setSize : function(w, h){
32020 this.field.setSize(w, h);
32027 * Realigns the editor to the bound field based on the current alignment config value.
32029 realign : function(){
32030 this.el.alignTo(this.boundEl, this.alignment);
32034 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
32035 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
32037 completeEdit : function(remainVisible){
32041 var v = this.getValue();
32042 if(this.revertInvalid !== false && !this.field.isValid()){
32043 v = this.startValue;
32044 this.cancelEdit(true);
32046 if(String(v) === String(this.startValue) && this.ignoreNoChange){
32047 this.editing = false;
32051 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
32052 this.editing = false;
32053 if(this.updateEl && this.boundEl){
32054 this.boundEl.update(v);
32056 if(remainVisible !== true){
32059 this.fireEvent("complete", this, v, this.startValue);
32064 onShow : function(){
32066 if(this.hideEl !== false){
32067 this.boundEl.hide();
32070 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
32071 this.fixIEFocus = true;
32072 this.deferredFocus.defer(50, this);
32074 this.field.focus();
32076 this.fireEvent("startedit", this.boundEl, this.startValue);
32079 deferredFocus : function(){
32081 this.field.focus();
32086 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
32087 * reverted to the original starting value.
32088 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
32089 * cancel (defaults to false)
32091 cancelEdit : function(remainVisible){
32093 this.setValue(this.startValue);
32094 if(remainVisible !== true){
32101 onBlur : function(){
32102 if(this.allowBlur !== true && this.editing){
32103 this.completeEdit();
32108 onHide : function(){
32110 this.completeEdit();
32114 if(this.field.collapse){
32115 this.field.collapse();
32118 if(this.hideEl !== false){
32119 this.boundEl.show();
32122 Roo.QuickTips.enable();
32127 * Sets the data value of the editor
32128 * @param {Mixed} value Any valid value supported by the underlying field
32130 setValue : function(v){
32131 this.field.setValue(v);
32135 * Gets the data value of the editor
32136 * @return {Mixed} The data value
32138 getValue : function(){
32139 return this.field.getValue();
32143 * Ext JS Library 1.1.1
32144 * Copyright(c) 2006-2007, Ext JS, LLC.
32146 * Originally Released Under LGPL - original licence link has changed is not relivant.
32149 * <script type="text/javascript">
32153 * @class Roo.BasicDialog
32154 * @extends Roo.util.Observable
32155 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32157 var dlg = new Roo.BasicDialog("my-dlg", {
32166 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32167 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32168 dlg.addButton('Cancel', dlg.hide, dlg);
32171 <b>A Dialog should always be a direct child of the body element.</b>
32172 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32173 * @cfg {String} title Default text to display in the title bar (defaults to null)
32174 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32175 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32176 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32177 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32178 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32179 * (defaults to null with no animation)
32180 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32181 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32182 * property for valid values (defaults to 'all')
32183 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32184 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32185 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32186 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32187 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32188 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32189 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32190 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32191 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32192 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32193 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32194 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32195 * draggable = true (defaults to false)
32196 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32197 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32198 * shadow (defaults to false)
32199 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32200 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32201 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32202 * @cfg {Array} buttons Array of buttons
32203 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32205 * Create a new BasicDialog.
32206 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32207 * @param {Object} config Configuration options
32209 Roo.BasicDialog = function(el, config){
32210 this.el = Roo.get(el);
32211 var dh = Roo.DomHelper;
32212 if(!this.el && config && config.autoCreate){
32213 if(typeof config.autoCreate == "object"){
32214 if(!config.autoCreate.id){
32215 config.autoCreate.id = el;
32217 this.el = dh.append(document.body,
32218 config.autoCreate, true);
32220 this.el = dh.append(document.body,
32221 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32225 el.setDisplayed(true);
32226 el.hide = this.hideAction;
32228 el.addClass("x-dlg");
32230 Roo.apply(this, config);
32232 this.proxy = el.createProxy("x-dlg-proxy");
32233 this.proxy.hide = this.hideAction;
32234 this.proxy.setOpacity(.5);
32238 el.setWidth(config.width);
32241 el.setHeight(config.height);
32243 this.size = el.getSize();
32244 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32245 this.xy = [config.x,config.y];
32247 this.xy = el.getCenterXY(true);
32249 /** The header element @type Roo.Element */
32250 this.header = el.child("> .x-dlg-hd");
32251 /** The body element @type Roo.Element */
32252 this.body = el.child("> .x-dlg-bd");
32253 /** The footer element @type Roo.Element */
32254 this.footer = el.child("> .x-dlg-ft");
32257 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32260 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32263 this.header.unselectable();
32265 this.header.update(this.title);
32267 // this element allows the dialog to be focused for keyboard event
32268 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32269 this.focusEl.swallowEvent("click", true);
32271 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32273 // wrap the body and footer for special rendering
32274 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32276 this.bwrap.dom.appendChild(this.footer.dom);
32279 this.bg = this.el.createChild({
32280 tag: "div", cls:"x-dlg-bg",
32281 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32283 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32286 if(this.autoScroll !== false && !this.autoTabs){
32287 this.body.setStyle("overflow", "auto");
32290 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32292 if(this.closable !== false){
32293 this.el.addClass("x-dlg-closable");
32294 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32295 this.close.on("click", this.closeClick, this);
32296 this.close.addClassOnOver("x-dlg-close-over");
32298 if(this.collapsible !== false){
32299 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32300 this.collapseBtn.on("click", this.collapseClick, this);
32301 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32302 this.header.on("dblclick", this.collapseClick, this);
32304 if(this.resizable !== false){
32305 this.el.addClass("x-dlg-resizable");
32306 this.resizer = new Roo.Resizable(el, {
32307 minWidth: this.minWidth || 80,
32308 minHeight:this.minHeight || 80,
32309 handles: this.resizeHandles || "all",
32312 this.resizer.on("beforeresize", this.beforeResize, this);
32313 this.resizer.on("resize", this.onResize, this);
32315 if(this.draggable !== false){
32316 el.addClass("x-dlg-draggable");
32317 if (!this.proxyDrag) {
32318 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32321 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32323 dd.setHandleElId(this.header.id);
32324 dd.endDrag = this.endMove.createDelegate(this);
32325 dd.startDrag = this.startMove.createDelegate(this);
32326 dd.onDrag = this.onDrag.createDelegate(this);
32331 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32332 this.mask.enableDisplayMode("block");
32334 this.el.addClass("x-dlg-modal");
32337 this.shadow = new Roo.Shadow({
32338 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32339 offset : this.shadowOffset
32342 this.shadowOffset = 0;
32344 if(Roo.useShims && this.shim !== false){
32345 this.shim = this.el.createShim();
32346 this.shim.hide = this.hideAction;
32354 if (this.buttons) {
32355 var bts= this.buttons;
32357 Roo.each(bts, function(b) {
32366 * Fires when a key is pressed
32367 * @param {Roo.BasicDialog} this
32368 * @param {Roo.EventObject} e
32373 * Fires when this dialog is moved by the user.
32374 * @param {Roo.BasicDialog} this
32375 * @param {Number} x The new page X
32376 * @param {Number} y The new page Y
32381 * Fires when this dialog is resized by the user.
32382 * @param {Roo.BasicDialog} this
32383 * @param {Number} width The new width
32384 * @param {Number} height The new height
32388 * @event beforehide
32389 * Fires before this dialog is hidden.
32390 * @param {Roo.BasicDialog} this
32392 "beforehide" : true,
32395 * Fires when this dialog is hidden.
32396 * @param {Roo.BasicDialog} this
32400 * @event beforeshow
32401 * Fires before this dialog is shown.
32402 * @param {Roo.BasicDialog} this
32404 "beforeshow" : true,
32407 * Fires when this dialog is shown.
32408 * @param {Roo.BasicDialog} this
32412 el.on("keydown", this.onKeyDown, this);
32413 el.on("mousedown", this.toFront, this);
32414 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32416 Roo.DialogManager.register(this);
32417 Roo.BasicDialog.superclass.constructor.call(this);
32420 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32421 shadowOffset: Roo.isIE ? 6 : 5,
32424 minButtonWidth: 75,
32425 defaultButton: null,
32426 buttonAlign: "right",
32431 * Sets the dialog title text
32432 * @param {String} text The title text to display
32433 * @return {Roo.BasicDialog} this
32435 setTitle : function(text){
32436 this.header.update(text);
32441 closeClick : function(){
32446 collapseClick : function(){
32447 this[this.collapsed ? "expand" : "collapse"]();
32451 * Collapses the dialog to its minimized state (only the title bar is visible).
32452 * Equivalent to the user clicking the collapse dialog button.
32454 collapse : function(){
32455 if(!this.collapsed){
32456 this.collapsed = true;
32457 this.el.addClass("x-dlg-collapsed");
32458 this.restoreHeight = this.el.getHeight();
32459 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32464 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32465 * clicking the expand dialog button.
32467 expand : function(){
32468 if(this.collapsed){
32469 this.collapsed = false;
32470 this.el.removeClass("x-dlg-collapsed");
32471 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32476 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32477 * @return {Roo.TabPanel} The tabs component
32479 initTabs : function(){
32480 var tabs = this.getTabs();
32481 while(tabs.getTab(0)){
32484 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32486 tabs.addTab(Roo.id(dom), dom.title);
32494 beforeResize : function(){
32495 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32499 onResize : function(){
32500 this.refreshSize();
32501 this.syncBodyHeight();
32502 this.adjustAssets();
32504 this.fireEvent("resize", this, this.size.width, this.size.height);
32508 onKeyDown : function(e){
32509 if(this.isVisible()){
32510 this.fireEvent("keydown", this, e);
32515 * Resizes the dialog.
32516 * @param {Number} width
32517 * @param {Number} height
32518 * @return {Roo.BasicDialog} this
32520 resizeTo : function(width, height){
32521 this.el.setSize(width, height);
32522 this.size = {width: width, height: height};
32523 this.syncBodyHeight();
32524 if(this.fixedcenter){
32527 if(this.isVisible()){
32528 this.constrainXY();
32529 this.adjustAssets();
32531 this.fireEvent("resize", this, width, height);
32537 * Resizes the dialog to fit the specified content size.
32538 * @param {Number} width
32539 * @param {Number} height
32540 * @return {Roo.BasicDialog} this
32542 setContentSize : function(w, h){
32543 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32544 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32545 //if(!this.el.isBorderBox()){
32546 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32547 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32550 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32551 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32553 this.resizeTo(w, h);
32558 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32559 * executed in response to a particular key being pressed while the dialog is active.
32560 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32561 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32562 * @param {Function} fn The function to call
32563 * @param {Object} scope (optional) The scope of the function
32564 * @return {Roo.BasicDialog} this
32566 addKeyListener : function(key, fn, scope){
32567 var keyCode, shift, ctrl, alt;
32568 if(typeof key == "object" && !(key instanceof Array)){
32569 keyCode = key["key"];
32570 shift = key["shift"];
32571 ctrl = key["ctrl"];
32576 var handler = function(dlg, e){
32577 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32578 var k = e.getKey();
32579 if(keyCode instanceof Array){
32580 for(var i = 0, len = keyCode.length; i < len; i++){
32581 if(keyCode[i] == k){
32582 fn.call(scope || window, dlg, k, e);
32588 fn.call(scope || window, dlg, k, e);
32593 this.on("keydown", handler);
32598 * Returns the TabPanel component (creates it if it doesn't exist).
32599 * Note: If you wish to simply check for the existence of tabs without creating them,
32600 * check for a null 'tabs' property.
32601 * @return {Roo.TabPanel} The tabs component
32603 getTabs : function(){
32605 this.el.addClass("x-dlg-auto-tabs");
32606 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32607 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32613 * Adds a button to the footer section of the dialog.
32614 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32615 * object or a valid Roo.DomHelper element config
32616 * @param {Function} handler The function called when the button is clicked
32617 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32618 * @return {Roo.Button} The new button
32620 addButton : function(config, handler, scope){
32621 var dh = Roo.DomHelper;
32623 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32625 if(!this.btnContainer){
32626 var tb = this.footer.createChild({
32628 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32629 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32631 this.btnContainer = tb.firstChild.firstChild.firstChild;
32636 minWidth: this.minButtonWidth,
32639 if(typeof config == "string"){
32640 bconfig.text = config;
32643 bconfig.dhconfig = config;
32645 Roo.apply(bconfig, config);
32649 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32650 bconfig.position = Math.max(0, bconfig.position);
32651 fc = this.btnContainer.childNodes[bconfig.position];
32654 var btn = new Roo.Button(
32656 this.btnContainer.insertBefore(document.createElement("td"),fc)
32657 : this.btnContainer.appendChild(document.createElement("td")),
32658 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32661 this.syncBodyHeight();
32664 * Array of all the buttons that have been added to this dialog via addButton
32669 this.buttons.push(btn);
32674 * Sets the default button to be focused when the dialog is displayed.
32675 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32676 * @return {Roo.BasicDialog} this
32678 setDefaultButton : function(btn){
32679 this.defaultButton = btn;
32684 getHeaderFooterHeight : function(safe){
32687 height += this.header.getHeight();
32690 var fm = this.footer.getMargins();
32691 height += (this.footer.getHeight()+fm.top+fm.bottom);
32693 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32694 height += this.centerBg.getPadding("tb");
32699 syncBodyHeight : function()
32701 var bd = this.body, // the text
32702 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32704 var height = this.size.height - this.getHeaderFooterHeight(false);
32705 bd.setHeight(height-bd.getMargins("tb"));
32706 var hh = this.header.getHeight();
32707 var h = this.size.height-hh;
32710 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32711 bw.setHeight(h-cb.getPadding("tb"));
32713 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32714 bd.setWidth(bw.getWidth(true));
32716 this.tabs.syncHeight();
32718 this.tabs.el.repaint();
32724 * Restores the previous state of the dialog if Roo.state is configured.
32725 * @return {Roo.BasicDialog} this
32727 restoreState : function(){
32728 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32729 if(box && box.width){
32730 this.xy = [box.x, box.y];
32731 this.resizeTo(box.width, box.height);
32737 beforeShow : function(){
32739 if(this.fixedcenter){
32740 this.xy = this.el.getCenterXY(true);
32743 Roo.get(document.body).addClass("x-body-masked");
32744 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32747 this.constrainXY();
32751 animShow : function(){
32752 var b = Roo.get(this.animateTarget).getBox();
32753 this.proxy.setSize(b.width, b.height);
32754 this.proxy.setLocation(b.x, b.y);
32756 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32757 true, .35, this.showEl.createDelegate(this));
32761 * Shows the dialog.
32762 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32763 * @return {Roo.BasicDialog} this
32765 show : function(animateTarget){
32766 if (this.fireEvent("beforeshow", this) === false){
32769 if(this.syncHeightBeforeShow){
32770 this.syncBodyHeight();
32771 }else if(this.firstShow){
32772 this.firstShow = false;
32773 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32775 this.animateTarget = animateTarget || this.animateTarget;
32776 if(!this.el.isVisible()){
32778 if(this.animateTarget && Roo.get(this.animateTarget)){
32788 showEl : function(){
32790 this.el.setXY(this.xy);
32792 this.adjustAssets(true);
32795 // IE peekaboo bug - fix found by Dave Fenwick
32799 this.fireEvent("show", this);
32803 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32804 * dialog itself will receive focus.
32806 focus : function(){
32807 if(this.defaultButton){
32808 this.defaultButton.focus();
32810 this.focusEl.focus();
32815 constrainXY : function(){
32816 if(this.constraintoviewport !== false){
32817 if(!this.viewSize){
32818 if(this.container){
32819 var s = this.container.getSize();
32820 this.viewSize = [s.width, s.height];
32822 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32825 var s = Roo.get(this.container||document).getScroll();
32827 var x = this.xy[0], y = this.xy[1];
32828 var w = this.size.width, h = this.size.height;
32829 var vw = this.viewSize[0], vh = this.viewSize[1];
32830 // only move it if it needs it
32832 // first validate right/bottom
32833 if(x + w > vw+s.left){
32837 if(y + h > vh+s.top){
32841 // then make sure top/left isn't negative
32853 if(this.isVisible()){
32854 this.el.setLocation(x, y);
32855 this.adjustAssets();
32862 onDrag : function(){
32863 if(!this.proxyDrag){
32864 this.xy = this.el.getXY();
32865 this.adjustAssets();
32870 adjustAssets : function(doShow){
32871 var x = this.xy[0], y = this.xy[1];
32872 var w = this.size.width, h = this.size.height;
32873 if(doShow === true){
32875 this.shadow.show(this.el);
32881 if(this.shadow && this.shadow.isVisible()){
32882 this.shadow.show(this.el);
32884 if(this.shim && this.shim.isVisible()){
32885 this.shim.setBounds(x, y, w, h);
32890 adjustViewport : function(w, h){
32892 w = Roo.lib.Dom.getViewWidth();
32893 h = Roo.lib.Dom.getViewHeight();
32896 this.viewSize = [w, h];
32897 if(this.modal && this.mask.isVisible()){
32898 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32899 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32901 if(this.isVisible()){
32902 this.constrainXY();
32907 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32908 * shadow, proxy, mask, etc.) Also removes all event listeners.
32909 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32911 destroy : function(removeEl){
32912 if(this.isVisible()){
32913 this.animateTarget = null;
32916 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32918 this.tabs.destroy(removeEl);
32931 for(var i = 0, len = this.buttons.length; i < len; i++){
32932 this.buttons[i].destroy();
32935 this.el.removeAllListeners();
32936 if(removeEl === true){
32937 this.el.update("");
32940 Roo.DialogManager.unregister(this);
32944 startMove : function(){
32945 if(this.proxyDrag){
32948 if(this.constraintoviewport !== false){
32949 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32954 endMove : function(){
32955 if(!this.proxyDrag){
32956 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32958 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32961 this.refreshSize();
32962 this.adjustAssets();
32964 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32968 * Brings this dialog to the front of any other visible dialogs
32969 * @return {Roo.BasicDialog} this
32971 toFront : function(){
32972 Roo.DialogManager.bringToFront(this);
32977 * Sends this dialog to the back (under) of any other visible dialogs
32978 * @return {Roo.BasicDialog} this
32980 toBack : function(){
32981 Roo.DialogManager.sendToBack(this);
32986 * Centers this dialog in the viewport
32987 * @return {Roo.BasicDialog} this
32989 center : function(){
32990 var xy = this.el.getCenterXY(true);
32991 this.moveTo(xy[0], xy[1]);
32996 * Moves the dialog's top-left corner to the specified point
32997 * @param {Number} x
32998 * @param {Number} y
32999 * @return {Roo.BasicDialog} this
33001 moveTo : function(x, y){
33003 if(this.isVisible()){
33004 this.el.setXY(this.xy);
33005 this.adjustAssets();
33011 * Aligns the dialog to the specified element
33012 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33013 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
33014 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33015 * @return {Roo.BasicDialog} this
33017 alignTo : function(element, position, offsets){
33018 this.xy = this.el.getAlignToXY(element, position, offsets);
33019 if(this.isVisible()){
33020 this.el.setXY(this.xy);
33021 this.adjustAssets();
33027 * Anchors an element to another element and realigns it when the window is resized.
33028 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33029 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
33030 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33031 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
33032 * is a number, it is used as the buffer delay (defaults to 50ms).
33033 * @return {Roo.BasicDialog} this
33035 anchorTo : function(el, alignment, offsets, monitorScroll){
33036 var action = function(){
33037 this.alignTo(el, alignment, offsets);
33039 Roo.EventManager.onWindowResize(action, this);
33040 var tm = typeof monitorScroll;
33041 if(tm != 'undefined'){
33042 Roo.EventManager.on(window, 'scroll', action, this,
33043 {buffer: tm == 'number' ? monitorScroll : 50});
33050 * Returns true if the dialog is visible
33051 * @return {Boolean}
33053 isVisible : function(){
33054 return this.el.isVisible();
33058 animHide : function(callback){
33059 var b = Roo.get(this.animateTarget).getBox();
33061 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
33063 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
33064 this.hideEl.createDelegate(this, [callback]));
33068 * Hides the dialog.
33069 * @param {Function} callback (optional) Function to call when the dialog is hidden
33070 * @return {Roo.BasicDialog} this
33072 hide : function(callback){
33073 if (this.fireEvent("beforehide", this) === false){
33077 this.shadow.hide();
33082 // sometimes animateTarget seems to get set.. causing problems...
33083 // this just double checks..
33084 if(this.animateTarget && Roo.get(this.animateTarget)) {
33085 this.animHide(callback);
33088 this.hideEl(callback);
33094 hideEl : function(callback){
33098 Roo.get(document.body).removeClass("x-body-masked");
33100 this.fireEvent("hide", this);
33101 if(typeof callback == "function"){
33107 hideAction : function(){
33108 this.setLeft("-10000px");
33109 this.setTop("-10000px");
33110 this.setStyle("visibility", "hidden");
33114 refreshSize : function(){
33115 this.size = this.el.getSize();
33116 this.xy = this.el.getXY();
33117 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
33121 // z-index is managed by the DialogManager and may be overwritten at any time
33122 setZIndex : function(index){
33124 this.mask.setStyle("z-index", index);
33127 this.shim.setStyle("z-index", ++index);
33130 this.shadow.setZIndex(++index);
33132 this.el.setStyle("z-index", ++index);
33134 this.proxy.setStyle("z-index", ++index);
33137 this.resizer.proxy.setStyle("z-index", ++index);
33140 this.lastZIndex = index;
33144 * Returns the element for this dialog
33145 * @return {Roo.Element} The underlying dialog Element
33147 getEl : function(){
33153 * @class Roo.DialogManager
33154 * Provides global access to BasicDialogs that have been created and
33155 * support for z-indexing (layering) multiple open dialogs.
33157 Roo.DialogManager = function(){
33159 var accessList = [];
33163 var sortDialogs = function(d1, d2){
33164 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33168 var orderDialogs = function(){
33169 accessList.sort(sortDialogs);
33170 var seed = Roo.DialogManager.zseed;
33171 for(var i = 0, len = accessList.length; i < len; i++){
33172 var dlg = accessList[i];
33174 dlg.setZIndex(seed + (i*10));
33181 * The starting z-index for BasicDialogs (defaults to 9000)
33182 * @type Number The z-index value
33187 register : function(dlg){
33188 list[dlg.id] = dlg;
33189 accessList.push(dlg);
33193 unregister : function(dlg){
33194 delete list[dlg.id];
33197 if(!accessList.indexOf){
33198 for( i = 0, len = accessList.length; i < len; i++){
33199 if(accessList[i] == dlg){
33200 accessList.splice(i, 1);
33205 i = accessList.indexOf(dlg);
33207 accessList.splice(i, 1);
33213 * Gets a registered dialog by id
33214 * @param {String/Object} id The id of the dialog or a dialog
33215 * @return {Roo.BasicDialog} this
33217 get : function(id){
33218 return typeof id == "object" ? id : list[id];
33222 * Brings the specified dialog to the front
33223 * @param {String/Object} dlg The id of the dialog or a dialog
33224 * @return {Roo.BasicDialog} this
33226 bringToFront : function(dlg){
33227 dlg = this.get(dlg);
33230 dlg._lastAccess = new Date().getTime();
33237 * Sends the specified dialog to the back
33238 * @param {String/Object} dlg The id of the dialog or a dialog
33239 * @return {Roo.BasicDialog} this
33241 sendToBack : function(dlg){
33242 dlg = this.get(dlg);
33243 dlg._lastAccess = -(new Date().getTime());
33249 * Hides all dialogs
33251 hideAll : function(){
33252 for(var id in list){
33253 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33262 * @class Roo.LayoutDialog
33263 * @extends Roo.BasicDialog
33264 * @children Roo.ContentPanel
33266 * Dialog which provides adjustments for working with a layout in a Dialog.
33267 * Add your necessary layout config options to the dialog's config.<br>
33268 * Example usage (including a nested layout):
33271 dialog = new Roo.LayoutDialog("download-dlg", {
33280 // layout config merges with the dialog config
33282 tabPosition: "top",
33283 alwaysShowTabs: true
33286 dialog.addKeyListener(27, dialog.hide, dialog);
33287 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33288 dialog.addButton("Build It!", this.getDownload, this);
33290 // we can even add nested layouts
33291 var innerLayout = new Roo.BorderLayout("dl-inner", {
33301 innerLayout.beginUpdate();
33302 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33303 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33304 innerLayout.endUpdate(true);
33306 var layout = dialog.getLayout();
33307 layout.beginUpdate();
33308 layout.add("center", new Roo.ContentPanel("standard-panel",
33309 {title: "Download the Source", fitToFrame:true}));
33310 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33311 {title: "Build your own roo.js"}));
33312 layout.getRegion("center").showPanel(sp);
33313 layout.endUpdate();
33317 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33318 * @param {Object} config configuration options
33320 Roo.LayoutDialog = function(el, cfg){
33323 if (typeof(cfg) == 'undefined') {
33324 config = Roo.apply({}, el);
33325 // not sure why we use documentElement here.. - it should always be body.
33326 // IE7 borks horribly if we use documentElement.
33327 // webkit also does not like documentElement - it creates a body element...
33328 el = Roo.get( document.body || document.documentElement ).createChild();
33329 //config.autoCreate = true;
33333 config.autoTabs = false;
33334 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33335 this.body.setStyle({overflow:"hidden", position:"relative"});
33336 this.layout = new Roo.BorderLayout(this.body.dom, config);
33337 this.layout.monitorWindowResize = false;
33338 this.el.addClass("x-dlg-auto-layout");
33339 // fix case when center region overwrites center function
33340 this.center = Roo.BasicDialog.prototype.center;
33341 this.on("show", this.layout.layout, this.layout, true);
33342 if (config.items) {
33343 var xitems = config.items;
33344 delete config.items;
33345 Roo.each(xitems, this.addxtype, this);
33350 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33354 * @cfg {Roo.LayoutRegion} east
33357 * @cfg {Roo.LayoutRegion} west
33360 * @cfg {Roo.LayoutRegion} south
33363 * @cfg {Roo.LayoutRegion} north
33366 * @cfg {Roo.LayoutRegion} center
33369 * @cfg {Roo.Button} buttons[] Bottom buttons..
33374 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33377 endUpdate : function(){
33378 this.layout.endUpdate();
33382 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33385 beginUpdate : function(){
33386 this.layout.beginUpdate();
33390 * Get the BorderLayout for this dialog
33391 * @return {Roo.BorderLayout}
33393 getLayout : function(){
33394 return this.layout;
33397 showEl : function(){
33398 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33400 this.layout.layout();
33405 // Use the syncHeightBeforeShow config option to control this automatically
33406 syncBodyHeight : function(){
33407 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33408 if(this.layout){this.layout.layout();}
33412 * Add an xtype element (actually adds to the layout.)
33413 * @return {Object} xdata xtype object data.
33416 addxtype : function(c) {
33417 return this.layout.addxtype(c);
33421 * Ext JS Library 1.1.1
33422 * Copyright(c) 2006-2007, Ext JS, LLC.
33424 * Originally Released Under LGPL - original licence link has changed is not relivant.
33427 * <script type="text/javascript">
33431 * @class Roo.MessageBox
33432 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33436 Roo.Msg.alert('Status', 'Changes saved successfully.');
33438 // Prompt for user data:
33439 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33441 // process text value...
33445 // Show a dialog using config options:
33447 title:'Save Changes?',
33448 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33449 buttons: Roo.Msg.YESNOCANCEL,
33456 Roo.MessageBox = function(){
33457 var dlg, opt, mask, waitTimer;
33458 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33459 var buttons, activeTextEl, bwidth;
33462 var handleButton = function(button){
33464 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33468 var handleHide = function(){
33469 if(opt && opt.cls){
33470 dlg.el.removeClass(opt.cls);
33473 Roo.TaskMgr.stop(waitTimer);
33479 var updateButtons = function(b){
33482 buttons["ok"].hide();
33483 buttons["cancel"].hide();
33484 buttons["yes"].hide();
33485 buttons["no"].hide();
33486 dlg.footer.dom.style.display = 'none';
33489 dlg.footer.dom.style.display = '';
33490 for(var k in buttons){
33491 if(typeof buttons[k] != "function"){
33494 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33495 width += buttons[k].el.getWidth()+15;
33505 var handleEsc = function(d, k, e){
33506 if(opt && opt.closable !== false){
33516 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33517 * @return {Roo.BasicDialog} The BasicDialog element
33519 getDialog : function(){
33521 dlg = new Roo.BasicDialog("x-msg-box", {
33526 constraintoviewport:false,
33528 collapsible : false,
33531 width:400, height:100,
33532 buttonAlign:"center",
33533 closeClick : function(){
33534 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33535 handleButton("no");
33537 handleButton("cancel");
33541 dlg.on("hide", handleHide);
33543 dlg.addKeyListener(27, handleEsc);
33545 var bt = this.buttonText;
33546 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33547 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33548 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33549 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33550 bodyEl = dlg.body.createChild({
33552 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>'
33554 msgEl = bodyEl.dom.firstChild;
33555 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33556 textboxEl.enableDisplayMode();
33557 textboxEl.addKeyListener([10,13], function(){
33558 if(dlg.isVisible() && opt && opt.buttons){
33559 if(opt.buttons.ok){
33560 handleButton("ok");
33561 }else if(opt.buttons.yes){
33562 handleButton("yes");
33566 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33567 textareaEl.enableDisplayMode();
33568 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33569 progressEl.enableDisplayMode();
33570 var pf = progressEl.dom.firstChild;
33572 pp = Roo.get(pf.firstChild);
33573 pp.setHeight(pf.offsetHeight);
33581 * Updates the message box body text
33582 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33583 * the XHTML-compliant non-breaking space character '&#160;')
33584 * @return {Roo.MessageBox} This message box
33586 updateText : function(text){
33587 if(!dlg.isVisible() && !opt.width){
33588 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33590 msgEl.innerHTML = text || ' ';
33592 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33593 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33595 Math.min(opt.width || cw , this.maxWidth),
33596 Math.max(opt.minWidth || this.minWidth, bwidth)
33599 activeTextEl.setWidth(w);
33601 if(dlg.isVisible()){
33602 dlg.fixedcenter = false;
33604 // to big, make it scroll. = But as usual stupid IE does not support
33607 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33608 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33609 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33611 bodyEl.dom.style.height = '';
33612 bodyEl.dom.style.overflowY = '';
33615 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33617 bodyEl.dom.style.overflowX = '';
33620 dlg.setContentSize(w, bodyEl.getHeight());
33621 if(dlg.isVisible()){
33622 dlg.fixedcenter = true;
33628 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33629 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33630 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33631 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33632 * @return {Roo.MessageBox} This message box
33634 updateProgress : function(value, text){
33636 this.updateText(text);
33638 if (pp) { // weird bug on my firefox - for some reason this is not defined
33639 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33645 * Returns true if the message box is currently displayed
33646 * @return {Boolean} True if the message box is visible, else false
33648 isVisible : function(){
33649 return dlg && dlg.isVisible();
33653 * Hides the message box if it is displayed
33656 if(this.isVisible()){
33662 * Displays a new message box, or reinitializes an existing message box, based on the config options
33663 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33664 * The following config object properties are supported:
33666 Property Type Description
33667 ---------- --------------- ------------------------------------------------------------------------------------
33668 animEl String/Element An id or Element from which the message box should animate as it opens and
33669 closes (defaults to undefined)
33670 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33671 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33672 closable Boolean False to hide the top-right close button (defaults to true). Note that
33673 progress and wait dialogs will ignore this property and always hide the
33674 close button as they can only be closed programmatically.
33675 cls String A custom CSS class to apply to the message box element
33676 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33677 displayed (defaults to 75)
33678 fn Function A callback function to execute after closing the dialog. The arguments to the
33679 function will be btn (the name of the button that was clicked, if applicable,
33680 e.g. "ok"), and text (the value of the active text field, if applicable).
33681 Progress and wait dialogs will ignore this option since they do not respond to
33682 user actions and can only be closed programmatically, so any required function
33683 should be called by the same code after it closes the dialog.
33684 icon String A CSS class that provides a background image to be used as an icon for
33685 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33686 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33687 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33688 modal Boolean False to allow user interaction with the page while the message box is
33689 displayed (defaults to true)
33690 msg String A string that will replace the existing message box body text (defaults
33691 to the XHTML-compliant non-breaking space character ' ')
33692 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33693 progress Boolean True to display a progress bar (defaults to false)
33694 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33695 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33696 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33697 title String The title text
33698 value String The string value to set into the active textbox element if displayed
33699 wait Boolean True to display a progress bar (defaults to false)
33700 width Number The width of the dialog in pixels
33707 msg: 'Please enter your address:',
33709 buttons: Roo.MessageBox.OKCANCEL,
33712 animEl: 'addAddressBtn'
33715 * @param {Object} config Configuration options
33716 * @return {Roo.MessageBox} This message box
33718 show : function(options)
33721 // this causes nightmares if you show one dialog after another
33722 // especially on callbacks..
33724 if(this.isVisible()){
33727 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33728 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33729 Roo.log("New Dialog Message:" + options.msg )
33730 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33731 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33734 var d = this.getDialog();
33736 d.setTitle(opt.title || " ");
33737 d.close.setDisplayed(opt.closable !== false);
33738 activeTextEl = textboxEl;
33739 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33744 textareaEl.setHeight(typeof opt.multiline == "number" ?
33745 opt.multiline : this.defaultTextHeight);
33746 activeTextEl = textareaEl;
33755 progressEl.setDisplayed(opt.progress === true);
33756 this.updateProgress(0);
33757 activeTextEl.dom.value = opt.value || "";
33759 dlg.setDefaultButton(activeTextEl);
33761 var bs = opt.buttons;
33764 db = buttons["ok"];
33765 }else if(bs && bs.yes){
33766 db = buttons["yes"];
33768 dlg.setDefaultButton(db);
33770 bwidth = updateButtons(opt.buttons);
33771 this.updateText(opt.msg);
33773 d.el.addClass(opt.cls);
33775 d.proxyDrag = opt.proxyDrag === true;
33776 d.modal = opt.modal !== false;
33777 d.mask = opt.modal !== false ? mask : false;
33778 if(!d.isVisible()){
33779 // force it to the end of the z-index stack so it gets a cursor in FF
33780 document.body.appendChild(dlg.el.dom);
33781 d.animateTarget = null;
33782 d.show(options.animEl);
33788 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33789 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33790 * and closing the message box when the process is complete.
33791 * @param {String} title The title bar text
33792 * @param {String} msg The message box body text
33793 * @return {Roo.MessageBox} This message box
33795 progress : function(title, msg){
33802 minWidth: this.minProgressWidth,
33809 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33810 * If a callback function is passed it will be called after the user clicks the button, and the
33811 * id of the button that was clicked will be passed as the only parameter to the callback
33812 * (could also be the top-right close button).
33813 * @param {String} title The title bar text
33814 * @param {String} msg The message box body text
33815 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33816 * @param {Object} scope (optional) The scope of the callback function
33817 * @return {Roo.MessageBox} This message box
33819 alert : function(title, msg, fn, scope){
33832 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33833 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33834 * You are responsible for closing the message box when the process is complete.
33835 * @param {String} msg The message box body text
33836 * @param {String} title (optional) The title bar text
33837 * @return {Roo.MessageBox} This message box
33839 wait : function(msg, title){
33850 waitTimer = Roo.TaskMgr.start({
33852 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33860 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33861 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33862 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33863 * @param {String} title The title bar text
33864 * @param {String} msg The message box body text
33865 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33866 * @param {Object} scope (optional) The scope of the callback function
33867 * @return {Roo.MessageBox} This message box
33869 confirm : function(title, msg, fn, scope){
33873 buttons: this.YESNO,
33882 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33883 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33884 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33885 * (could also be the top-right close button) and the text that was entered will be passed as the two
33886 * parameters to the callback.
33887 * @param {String} title The title bar text
33888 * @param {String} msg The message box body text
33889 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33890 * @param {Object} scope (optional) The scope of the callback function
33891 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33892 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33893 * @return {Roo.MessageBox} This message box
33895 prompt : function(title, msg, fn, scope, multiline){
33899 buttons: this.OKCANCEL,
33904 multiline: multiline,
33911 * Button config that displays a single OK button
33916 * Button config that displays Yes and No buttons
33919 YESNO : {yes:true, no:true},
33921 * Button config that displays OK and Cancel buttons
33924 OKCANCEL : {ok:true, cancel:true},
33926 * Button config that displays Yes, No and Cancel buttons
33929 YESNOCANCEL : {yes:true, no:true, cancel:true},
33932 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33935 defaultTextHeight : 75,
33937 * The maximum width in pixels of the message box (defaults to 600)
33942 * The minimum width in pixels of the message box (defaults to 100)
33947 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33948 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33951 minProgressWidth : 250,
33953 * An object containing the default button text strings that can be overriden for localized language support.
33954 * Supported properties are: ok, cancel, yes and no.
33955 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33968 * Shorthand for {@link Roo.MessageBox}
33970 Roo.Msg = Roo.MessageBox;/*
33972 * Ext JS Library 1.1.1
33973 * Copyright(c) 2006-2007, Ext JS, LLC.
33975 * Originally Released Under LGPL - original licence link has changed is not relivant.
33978 * <script type="text/javascript">
33981 * @class Roo.QuickTips
33982 * Provides attractive and customizable tooltips for any element.
33985 Roo.QuickTips = function(){
33986 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33987 var ce, bd, xy, dd;
33988 var visible = false, disabled = true, inited = false;
33989 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33991 var onOver = function(e){
33995 var t = e.getTarget();
33996 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33999 if(ce && t == ce.el){
34000 clearTimeout(hideProc);
34003 if(t && tagEls[t.id]){
34004 tagEls[t.id].el = t;
34005 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
34008 var ttp, et = Roo.fly(t);
34009 var ns = cfg.namespace;
34010 if(tm.interceptTitles && t.title){
34013 t.removeAttribute("title");
34014 e.preventDefault();
34016 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
34019 showProc = show.defer(tm.showDelay, tm, [{
34021 text: ttp.replace(/\\n/g,'<br/>'),
34022 width: et.getAttributeNS(ns, cfg.width),
34023 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
34024 title: et.getAttributeNS(ns, cfg.title),
34025 cls: et.getAttributeNS(ns, cfg.cls)
34030 var onOut = function(e){
34031 clearTimeout(showProc);
34032 var t = e.getTarget();
34033 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
34034 hideProc = setTimeout(hide, tm.hideDelay);
34038 var onMove = function(e){
34044 if(tm.trackMouse && ce){
34049 var onDown = function(e){
34050 clearTimeout(showProc);
34051 clearTimeout(hideProc);
34053 if(tm.hideOnClick){
34056 tm.enable.defer(100, tm);
34061 var getPad = function(){
34062 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
34065 var show = function(o){
34069 clearTimeout(dismissProc);
34071 if(removeCls){ // in case manually hidden
34072 el.removeClass(removeCls);
34076 el.addClass(ce.cls);
34077 removeCls = ce.cls;
34080 tipTitle.update(ce.title);
34083 tipTitle.update('');
34086 el.dom.style.width = tm.maxWidth+'px';
34087 //tipBody.dom.style.width = '';
34088 tipBodyText.update(o.text);
34089 var p = getPad(), w = ce.width;
34091 var td = tipBodyText.dom;
34092 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
34093 if(aw > tm.maxWidth){
34095 }else if(aw < tm.minWidth){
34101 //tipBody.setWidth(w);
34102 el.setWidth(parseInt(w, 10) + p);
34103 if(ce.autoHide === false){
34104 close.setDisplayed(true);
34109 close.setDisplayed(false);
34115 el.avoidY = xy[1]-18;
34120 el.setStyle("visibility", "visible");
34121 el.fadeIn({callback: afterShow});
34127 var afterShow = function(){
34131 if(tm.autoDismiss && ce.autoHide !== false){
34132 dismissProc = setTimeout(hide, tm.autoDismissDelay);
34137 var hide = function(noanim){
34138 clearTimeout(dismissProc);
34139 clearTimeout(hideProc);
34141 if(el.isVisible()){
34143 if(noanim !== true && tm.animate){
34144 el.fadeOut({callback: afterHide});
34151 var afterHide = function(){
34154 el.removeClass(removeCls);
34161 * @cfg {Number} minWidth
34162 * The minimum width of the quick tip (defaults to 40)
34166 * @cfg {Number} maxWidth
34167 * The maximum width of the quick tip (defaults to 300)
34171 * @cfg {Boolean} interceptTitles
34172 * True to automatically use the element's DOM title value if available (defaults to false)
34174 interceptTitles : false,
34176 * @cfg {Boolean} trackMouse
34177 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34179 trackMouse : false,
34181 * @cfg {Boolean} hideOnClick
34182 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34184 hideOnClick : true,
34186 * @cfg {Number} showDelay
34187 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
34191 * @cfg {Number} hideDelay
34192 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34196 * @cfg {Boolean} autoHide
34197 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34198 * Used in conjunction with hideDelay.
34203 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34204 * (defaults to true). Used in conjunction with autoDismissDelay.
34206 autoDismiss : true,
34209 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34211 autoDismissDelay : 5000,
34213 * @cfg {Boolean} animate
34214 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34219 * @cfg {String} title
34220 * Title text to display (defaults to ''). This can be any valid HTML markup.
34224 * @cfg {String} text
34225 * Body text to display (defaults to ''). This can be any valid HTML markup.
34229 * @cfg {String} cls
34230 * A CSS class to apply to the base quick tip element (defaults to '').
34234 * @cfg {Number} width
34235 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34236 * minWidth or maxWidth.
34241 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34242 * or display QuickTips in a page.
34245 tm = Roo.QuickTips;
34246 cfg = tm.tagConfig;
34248 if(!Roo.isReady){ // allow calling of init() before onReady
34249 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34252 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34253 el.fxDefaults = {stopFx: true};
34254 // maximum custom styling
34255 //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>');
34256 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>');
34257 tipTitle = el.child('h3');
34258 tipTitle.enableDisplayMode("block");
34259 tipBody = el.child('div.x-tip-bd');
34260 tipBodyText = el.child('div.x-tip-bd-inner');
34261 //bdLeft = el.child('div.x-tip-bd-left');
34262 //bdRight = el.child('div.x-tip-bd-right');
34263 close = el.child('div.x-tip-close');
34264 close.enableDisplayMode("block");
34265 close.on("click", hide);
34266 var d = Roo.get(document);
34267 d.on("mousedown", onDown);
34268 d.on("mouseover", onOver);
34269 d.on("mouseout", onOut);
34270 d.on("mousemove", onMove);
34271 esc = d.addKeyListener(27, hide);
34274 dd = el.initDD("default", null, {
34275 onDrag : function(){
34279 dd.setHandleElId(tipTitle.id);
34288 * Configures a new quick tip instance and assigns it to a target element. The following config options
34291 Property Type Description
34292 ---------- --------------------- ------------------------------------------------------------------------
34293 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34295 * @param {Object} config The config object
34297 register : function(config){
34298 var cs = config instanceof Array ? config : arguments;
34299 for(var i = 0, len = cs.length; i < len; i++) {
34301 var target = c.target;
34303 if(target instanceof Array){
34304 for(var j = 0, jlen = target.length; j < jlen; j++){
34305 tagEls[target[j]] = c;
34308 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34315 * Removes this quick tip from its element and destroys it.
34316 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34318 unregister : function(el){
34319 delete tagEls[Roo.id(el)];
34323 * Enable this quick tip.
34325 enable : function(){
34326 if(inited && disabled){
34328 if(locks.length < 1){
34335 * Disable this quick tip.
34337 disable : function(){
34339 clearTimeout(showProc);
34340 clearTimeout(hideProc);
34341 clearTimeout(dismissProc);
34349 * Returns true if the quick tip is enabled, else false.
34351 isEnabled : function(){
34357 namespace : "roo", // was ext?? this may break..
34358 alt_namespace : "ext",
34359 attribute : "qtip",
34369 // backwards compat
34370 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34372 * Ext JS Library 1.1.1
34373 * Copyright(c) 2006-2007, Ext JS, LLC.
34375 * Originally Released Under LGPL - original licence link has changed is not relivant.
34378 * <script type="text/javascript">
34383 * @class Roo.tree.TreePanel
34384 * @extends Roo.data.Tree
34385 * @cfg {Roo.tree.TreeNode} root The root node
34386 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34387 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34388 * @cfg {Boolean} enableDD true to enable drag and drop
34389 * @cfg {Boolean} enableDrag true to enable just drag
34390 * @cfg {Boolean} enableDrop true to enable just drop
34391 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34392 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34393 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34394 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34395 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34396 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34397 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34398 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34399 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34400 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34401 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34402 * @cfg {Roo.tree.TreeLoader} loader A TreeLoader for use with this TreePanel
34403 * @cfg {Roo.tree.TreeEditor} editor The TreeEditor to display when clicked.
34404 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34405 * @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>
34406 * @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>
34409 * @param {String/HTMLElement/Element} el The container element
34410 * @param {Object} config
34412 Roo.tree.TreePanel = function(el, config){
34414 var loader = false;
34416 root = config.root;
34417 delete config.root;
34419 if (config.loader) {
34420 loader = config.loader;
34421 delete config.loader;
34424 Roo.apply(this, config);
34425 Roo.tree.TreePanel.superclass.constructor.call(this);
34426 this.el = Roo.get(el);
34427 this.el.addClass('x-tree');
34428 //console.log(root);
34430 this.setRootNode( Roo.factory(root, Roo.tree));
34433 this.loader = Roo.factory(loader, Roo.tree);
34436 * Read-only. The id of the container element becomes this TreePanel's id.
34438 this.id = this.el.id;
34441 * @event beforeload
34442 * Fires before a node is loaded, return false to cancel
34443 * @param {Node} node The node being loaded
34445 "beforeload" : true,
34448 * Fires when a node is loaded
34449 * @param {Node} node The node that was loaded
34453 * @event textchange
34454 * Fires when the text for a node is changed
34455 * @param {Node} node The node
34456 * @param {String} text The new text
34457 * @param {String} oldText The old text
34459 "textchange" : true,
34461 * @event beforeexpand
34462 * Fires before a node is expanded, return false to cancel.
34463 * @param {Node} node The node
34464 * @param {Boolean} deep
34465 * @param {Boolean} anim
34467 "beforeexpand" : true,
34469 * @event beforecollapse
34470 * Fires before a node is collapsed, return false to cancel.
34471 * @param {Node} node The node
34472 * @param {Boolean} deep
34473 * @param {Boolean} anim
34475 "beforecollapse" : true,
34478 * Fires when a node is expanded
34479 * @param {Node} node The node
34483 * @event disabledchange
34484 * Fires when the disabled status of a node changes
34485 * @param {Node} node The node
34486 * @param {Boolean} disabled
34488 "disabledchange" : true,
34491 * Fires when a node is collapsed
34492 * @param {Node} node The node
34496 * @event beforeclick
34497 * Fires before click processing on a node. Return false to cancel the default action.
34498 * @param {Node} node The node
34499 * @param {Roo.EventObject} e The event object
34501 "beforeclick":true,
34503 * @event checkchange
34504 * Fires when a node with a checkbox's checked property changes
34505 * @param {Node} this This node
34506 * @param {Boolean} checked
34508 "checkchange":true,
34511 * Fires when a node is clicked
34512 * @param {Node} node The node
34513 * @param {Roo.EventObject} e The event object
34518 * Fires when a node is double clicked
34519 * @param {Node} node The node
34520 * @param {Roo.EventObject} e The event object
34524 * @event contextmenu
34525 * Fires when a node is right clicked
34526 * @param {Node} node The node
34527 * @param {Roo.EventObject} e The event object
34529 "contextmenu":true,
34531 * @event beforechildrenrendered
34532 * Fires right before the child nodes for a node are rendered
34533 * @param {Node} node The node
34535 "beforechildrenrendered":true,
34538 * Fires when a node starts being dragged
34539 * @param {Roo.tree.TreePanel} this
34540 * @param {Roo.tree.TreeNode} node
34541 * @param {event} e The raw browser event
34543 "startdrag" : true,
34546 * Fires when a drag operation is complete
34547 * @param {Roo.tree.TreePanel} this
34548 * @param {Roo.tree.TreeNode} node
34549 * @param {event} e The raw browser event
34554 * Fires when a dragged node is dropped on a valid DD target
34555 * @param {Roo.tree.TreePanel} this
34556 * @param {Roo.tree.TreeNode} node
34557 * @param {DD} dd The dd it was dropped on
34558 * @param {event} e The raw browser event
34562 * @event beforenodedrop
34563 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34564 * passed to handlers has the following properties:<br />
34565 * <ul style="padding:5px;padding-left:16px;">
34566 * <li>tree - The TreePanel</li>
34567 * <li>target - The node being targeted for the drop</li>
34568 * <li>data - The drag data from the drag source</li>
34569 * <li>point - The point of the drop - append, above or below</li>
34570 * <li>source - The drag source</li>
34571 * <li>rawEvent - Raw mouse event</li>
34572 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34573 * to be inserted by setting them on this object.</li>
34574 * <li>cancel - Set this to true to cancel the drop.</li>
34576 * @param {Object} dropEvent
34578 "beforenodedrop" : true,
34581 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34582 * passed to handlers has the following properties:<br />
34583 * <ul style="padding:5px;padding-left:16px;">
34584 * <li>tree - The TreePanel</li>
34585 * <li>target - The node being targeted for the drop</li>
34586 * <li>data - The drag data from the drag source</li>
34587 * <li>point - The point of the drop - append, above or below</li>
34588 * <li>source - The drag source</li>
34589 * <li>rawEvent - Raw mouse event</li>
34590 * <li>dropNode - Dropped node(s).</li>
34592 * @param {Object} dropEvent
34596 * @event nodedragover
34597 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34598 * passed to handlers has the following properties:<br />
34599 * <ul style="padding:5px;padding-left:16px;">
34600 * <li>tree - The TreePanel</li>
34601 * <li>target - The node being targeted for the drop</li>
34602 * <li>data - The drag data from the drag source</li>
34603 * <li>point - The point of the drop - append, above or below</li>
34604 * <li>source - The drag source</li>
34605 * <li>rawEvent - Raw mouse event</li>
34606 * <li>dropNode - Drop node(s) provided by the source.</li>
34607 * <li>cancel - Set this to true to signal drop not allowed.</li>
34609 * @param {Object} dragOverEvent
34611 "nodedragover" : true,
34613 * @event appendnode
34614 * Fires when append node to the tree
34615 * @param {Roo.tree.TreePanel} this
34616 * @param {Roo.tree.TreeNode} node
34617 * @param {Number} index The index of the newly appended node
34619 "appendnode" : true
34622 if(this.singleExpand){
34623 this.on("beforeexpand", this.restrictExpand, this);
34626 this.editor.tree = this;
34627 this.editor = Roo.factory(this.editor, Roo.tree);
34630 if (this.selModel) {
34631 this.selModel = Roo.factory(this.selModel, Roo.tree);
34635 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34636 rootVisible : true,
34637 animate: Roo.enableFx,
34640 hlDrop : Roo.enableFx,
34644 rendererTip: false,
34646 restrictExpand : function(node){
34647 var p = node.parentNode;
34649 if(p.expandedChild && p.expandedChild.parentNode == p){
34650 p.expandedChild.collapse();
34652 p.expandedChild = node;
34656 // private override
34657 setRootNode : function(node){
34658 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34659 if(!this.rootVisible){
34660 node.ui = new Roo.tree.RootTreeNodeUI(node);
34666 * Returns the container element for this TreePanel
34668 getEl : function(){
34673 * Returns the default TreeLoader for this TreePanel
34675 getLoader : function(){
34676 return this.loader;
34682 expandAll : function(){
34683 this.root.expand(true);
34687 * Collapse all nodes
34689 collapseAll : function(){
34690 this.root.collapse(true);
34694 * Returns the selection model used by this TreePanel
34696 getSelectionModel : function(){
34697 if(!this.selModel){
34698 this.selModel = new Roo.tree.DefaultSelectionModel();
34700 return this.selModel;
34704 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34705 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34706 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34709 getChecked : function(a, startNode){
34710 startNode = startNode || this.root;
34712 var f = function(){
34713 if(this.attributes.checked){
34714 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34717 startNode.cascade(f);
34722 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34723 * @param {String} path
34724 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34725 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34726 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34728 expandPath : function(path, attr, callback){
34729 attr = attr || "id";
34730 var keys = path.split(this.pathSeparator);
34731 var curNode = this.root;
34732 if(curNode.attributes[attr] != keys[1]){ // invalid root
34734 callback(false, null);
34739 var f = function(){
34740 if(++index == keys.length){
34742 callback(true, curNode);
34746 var c = curNode.findChild(attr, keys[index]);
34749 callback(false, curNode);
34754 c.expand(false, false, f);
34756 curNode.expand(false, false, f);
34760 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34761 * @param {String} path
34762 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34763 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34764 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34766 selectPath : function(path, attr, callback){
34767 attr = attr || "id";
34768 var keys = path.split(this.pathSeparator);
34769 var v = keys.pop();
34770 if(keys.length > 0){
34771 var f = function(success, node){
34772 if(success && node){
34773 var n = node.findChild(attr, v);
34779 }else if(callback){
34780 callback(false, n);
34784 callback(false, n);
34788 this.expandPath(keys.join(this.pathSeparator), attr, f);
34790 this.root.select();
34792 callback(true, this.root);
34797 getTreeEl : function(){
34802 * Trigger rendering of this TreePanel
34804 render : function(){
34805 if (this.innerCt) {
34806 return this; // stop it rendering more than once!!
34809 this.innerCt = this.el.createChild({tag:"ul",
34810 cls:"x-tree-root-ct " +
34811 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34813 if(this.containerScroll){
34814 Roo.dd.ScrollManager.register(this.el);
34816 if((this.enableDD || this.enableDrop) && !this.dropZone){
34818 * The dropZone used by this tree if drop is enabled
34819 * @type Roo.tree.TreeDropZone
34821 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34822 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34825 if((this.enableDD || this.enableDrag) && !this.dragZone){
34827 * The dragZone used by this tree if drag is enabled
34828 * @type Roo.tree.TreeDragZone
34830 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34831 ddGroup: this.ddGroup || "TreeDD",
34832 scroll: this.ddScroll
34835 this.getSelectionModel().init(this);
34837 Roo.log("ROOT not set in tree");
34840 this.root.render();
34841 if(!this.rootVisible){
34842 this.root.renderChildren();
34848 * Ext JS Library 1.1.1
34849 * Copyright(c) 2006-2007, Ext JS, LLC.
34851 * Originally Released Under LGPL - original licence link has changed is not relivant.
34854 * <script type="text/javascript">
34859 * @class Roo.tree.DefaultSelectionModel
34860 * @extends Roo.util.Observable
34861 * The default single selection for a TreePanel.
34862 * @param {Object} cfg Configuration
34864 Roo.tree.DefaultSelectionModel = function(cfg){
34865 this.selNode = null;
34871 * @event selectionchange
34872 * Fires when the selected node changes
34873 * @param {DefaultSelectionModel} this
34874 * @param {TreeNode} node the new selection
34876 "selectionchange" : true,
34879 * @event beforeselect
34880 * Fires before the selected node changes, return false to cancel the change
34881 * @param {DefaultSelectionModel} this
34882 * @param {TreeNode} node the new selection
34883 * @param {TreeNode} node the old selection
34885 "beforeselect" : true
34888 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34891 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34892 init : function(tree){
34894 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34895 tree.on("click", this.onNodeClick, this);
34898 onNodeClick : function(node, e){
34899 if (e.ctrlKey && this.selNode == node) {
34900 this.unselect(node);
34908 * @param {TreeNode} node The node to select
34909 * @return {TreeNode} The selected node
34911 select : function(node){
34912 var last = this.selNode;
34913 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34915 last.ui.onSelectedChange(false);
34917 this.selNode = node;
34918 node.ui.onSelectedChange(true);
34919 this.fireEvent("selectionchange", this, node, last);
34926 * @param {TreeNode} node The node to unselect
34928 unselect : function(node){
34929 if(this.selNode == node){
34930 this.clearSelections();
34935 * Clear all selections
34937 clearSelections : function(){
34938 var n = this.selNode;
34940 n.ui.onSelectedChange(false);
34941 this.selNode = null;
34942 this.fireEvent("selectionchange", this, null);
34948 * Get the selected node
34949 * @return {TreeNode} The selected node
34951 getSelectedNode : function(){
34952 return this.selNode;
34956 * Returns true if the node is selected
34957 * @param {TreeNode} node The node to check
34958 * @return {Boolean}
34960 isSelected : function(node){
34961 return this.selNode == node;
34965 * Selects the node above the selected node in the tree, intelligently walking the nodes
34966 * @return TreeNode The new selection
34968 selectPrevious : function(){
34969 var s = this.selNode || this.lastSelNode;
34973 var ps = s.previousSibling;
34975 if(!ps.isExpanded() || ps.childNodes.length < 1){
34976 return this.select(ps);
34978 var lc = ps.lastChild;
34979 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34982 return this.select(lc);
34984 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34985 return this.select(s.parentNode);
34991 * Selects the node above the selected node in the tree, intelligently walking the nodes
34992 * @return TreeNode The new selection
34994 selectNext : function(){
34995 var s = this.selNode || this.lastSelNode;
34999 if(s.firstChild && s.isExpanded()){
35000 return this.select(s.firstChild);
35001 }else if(s.nextSibling){
35002 return this.select(s.nextSibling);
35003 }else if(s.parentNode){
35005 s.parentNode.bubble(function(){
35006 if(this.nextSibling){
35007 newS = this.getOwnerTree().selModel.select(this.nextSibling);
35016 onKeyDown : function(e){
35017 var s = this.selNode || this.lastSelNode;
35018 // undesirable, but required
35023 var k = e.getKey();
35031 this.selectPrevious();
35034 e.preventDefault();
35035 if(s.hasChildNodes()){
35036 if(!s.isExpanded()){
35038 }else if(s.firstChild){
35039 this.select(s.firstChild, e);
35044 e.preventDefault();
35045 if(s.hasChildNodes() && s.isExpanded()){
35047 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
35048 this.select(s.parentNode, e);
35056 * @class Roo.tree.MultiSelectionModel
35057 * @extends Roo.util.Observable
35058 * Multi selection for a TreePanel.
35059 * @param {Object} cfg Configuration
35061 Roo.tree.MultiSelectionModel = function(){
35062 this.selNodes = [];
35066 * @event selectionchange
35067 * Fires when the selected nodes change
35068 * @param {MultiSelectionModel} this
35069 * @param {Array} nodes Array of the selected nodes
35071 "selectionchange" : true
35073 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
35077 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
35078 init : function(tree){
35080 tree.getTreeEl().on("keydown", this.onKeyDown, this);
35081 tree.on("click", this.onNodeClick, this);
35084 onNodeClick : function(node, e){
35085 this.select(node, e, e.ctrlKey);
35090 * @param {TreeNode} node The node to select
35091 * @param {EventObject} e (optional) An event associated with the selection
35092 * @param {Boolean} keepExisting True to retain existing selections
35093 * @return {TreeNode} The selected node
35095 select : function(node, e, keepExisting){
35096 if(keepExisting !== true){
35097 this.clearSelections(true);
35099 if(this.isSelected(node)){
35100 this.lastSelNode = node;
35103 this.selNodes.push(node);
35104 this.selMap[node.id] = node;
35105 this.lastSelNode = node;
35106 node.ui.onSelectedChange(true);
35107 this.fireEvent("selectionchange", this, this.selNodes);
35113 * @param {TreeNode} node The node to unselect
35115 unselect : function(node){
35116 if(this.selMap[node.id]){
35117 node.ui.onSelectedChange(false);
35118 var sn = this.selNodes;
35121 index = sn.indexOf(node);
35123 for(var i = 0, len = sn.length; i < len; i++){
35131 this.selNodes.splice(index, 1);
35133 delete this.selMap[node.id];
35134 this.fireEvent("selectionchange", this, this.selNodes);
35139 * Clear all selections
35141 clearSelections : function(suppressEvent){
35142 var sn = this.selNodes;
35144 for(var i = 0, len = sn.length; i < len; i++){
35145 sn[i].ui.onSelectedChange(false);
35147 this.selNodes = [];
35149 if(suppressEvent !== true){
35150 this.fireEvent("selectionchange", this, this.selNodes);
35156 * Returns true if the node is selected
35157 * @param {TreeNode} node The node to check
35158 * @return {Boolean}
35160 isSelected : function(node){
35161 return this.selMap[node.id] ? true : false;
35165 * Returns an array of the selected nodes
35168 getSelectedNodes : function(){
35169 return this.selNodes;
35172 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35174 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35176 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35179 * Ext JS Library 1.1.1
35180 * Copyright(c) 2006-2007, Ext JS, LLC.
35182 * Originally Released Under LGPL - original licence link has changed is not relivant.
35185 * <script type="text/javascript">
35189 * @class Roo.tree.TreeNode
35190 * @extends Roo.data.Node
35191 * @cfg {String} text The text for this node
35192 * @cfg {Boolean} expanded true to start the node expanded
35193 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35194 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35195 * @cfg {Boolean} disabled true to start the node disabled
35196 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35197 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35198 * @cfg {String} cls A css class to be added to the node
35199 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35200 * @cfg {String} href URL of the link used for the node (defaults to #)
35201 * @cfg {String} hrefTarget target frame for the link
35202 * @cfg {String} qtip An Ext QuickTip for the node
35203 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35204 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35205 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35206 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35207 * (defaults to undefined with no checkbox rendered)
35209 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35211 Roo.tree.TreeNode = function(attributes){
35212 attributes = attributes || {};
35213 if(typeof attributes == "string"){
35214 attributes = {text: attributes};
35216 this.childrenRendered = false;
35217 this.rendered = false;
35218 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35219 this.expanded = attributes.expanded === true;
35220 this.isTarget = attributes.isTarget !== false;
35221 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35222 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35225 * Read-only. The text for this node. To change it use setText().
35228 this.text = attributes.text;
35230 * True if this node is disabled.
35233 this.disabled = attributes.disabled === true;
35237 * @event textchange
35238 * Fires when the text for this node is changed
35239 * @param {Node} this This node
35240 * @param {String} text The new text
35241 * @param {String} oldText The old text
35243 "textchange" : true,
35245 * @event beforeexpand
35246 * Fires before this node is expanded, return false to cancel.
35247 * @param {Node} this This node
35248 * @param {Boolean} deep
35249 * @param {Boolean} anim
35251 "beforeexpand" : true,
35253 * @event beforecollapse
35254 * Fires before this node is collapsed, return false to cancel.
35255 * @param {Node} this This node
35256 * @param {Boolean} deep
35257 * @param {Boolean} anim
35259 "beforecollapse" : true,
35262 * Fires when this node is expanded
35263 * @param {Node} this This node
35267 * @event disabledchange
35268 * Fires when the disabled status of this node changes
35269 * @param {Node} this This node
35270 * @param {Boolean} disabled
35272 "disabledchange" : true,
35275 * Fires when this node is collapsed
35276 * @param {Node} this This node
35280 * @event beforeclick
35281 * Fires before click processing. Return false to cancel the default action.
35282 * @param {Node} this This node
35283 * @param {Roo.EventObject} e The event object
35285 "beforeclick":true,
35287 * @event checkchange
35288 * Fires when a node with a checkbox's checked property changes
35289 * @param {Node} this This node
35290 * @param {Boolean} checked
35292 "checkchange":true,
35295 * Fires when this node is clicked
35296 * @param {Node} this This node
35297 * @param {Roo.EventObject} e The event object
35302 * Fires when this node is double clicked
35303 * @param {Node} this This node
35304 * @param {Roo.EventObject} e The event object
35308 * @event contextmenu
35309 * Fires when this node is right clicked
35310 * @param {Node} this This node
35311 * @param {Roo.EventObject} e The event object
35313 "contextmenu":true,
35315 * @event beforechildrenrendered
35316 * Fires right before the child nodes for this node are rendered
35317 * @param {Node} this This node
35319 "beforechildrenrendered":true
35322 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35325 * Read-only. The UI for this node
35328 this.ui = new uiClass(this);
35330 // finally support items[]
35331 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35336 Roo.each(this.attributes.items, function(c) {
35337 this.appendChild(Roo.factory(c,Roo.Tree));
35339 delete this.attributes.items;
35344 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35345 preventHScroll: true,
35347 * Returns true if this node is expanded
35348 * @return {Boolean}
35350 isExpanded : function(){
35351 return this.expanded;
35355 * Returns the UI object for this node
35356 * @return {TreeNodeUI}
35358 getUI : function(){
35362 // private override
35363 setFirstChild : function(node){
35364 var of = this.firstChild;
35365 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35366 if(this.childrenRendered && of && node != of){
35367 of.renderIndent(true, true);
35370 this.renderIndent(true, true);
35374 // private override
35375 setLastChild : function(node){
35376 var ol = this.lastChild;
35377 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35378 if(this.childrenRendered && ol && node != ol){
35379 ol.renderIndent(true, true);
35382 this.renderIndent(true, true);
35386 // these methods are overridden to provide lazy rendering support
35387 // private override
35388 appendChild : function()
35390 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35391 if(node && this.childrenRendered){
35394 this.ui.updateExpandIcon();
35398 // private override
35399 removeChild : function(node){
35400 this.ownerTree.getSelectionModel().unselect(node);
35401 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35402 // if it's been rendered remove dom node
35403 if(this.childrenRendered){
35406 if(this.childNodes.length < 1){
35407 this.collapse(false, false);
35409 this.ui.updateExpandIcon();
35411 if(!this.firstChild) {
35412 this.childrenRendered = false;
35417 // private override
35418 insertBefore : function(node, refNode){
35419 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35420 if(newNode && refNode && this.childrenRendered){
35423 this.ui.updateExpandIcon();
35428 * Sets the text for this node
35429 * @param {String} text
35431 setText : function(text){
35432 var oldText = this.text;
35434 this.attributes.text = text;
35435 if(this.rendered){ // event without subscribing
35436 this.ui.onTextChange(this, text, oldText);
35438 this.fireEvent("textchange", this, text, oldText);
35442 * Triggers selection of this node
35444 select : function(){
35445 this.getOwnerTree().getSelectionModel().select(this);
35449 * Triggers deselection of this node
35451 unselect : function(){
35452 this.getOwnerTree().getSelectionModel().unselect(this);
35456 * Returns true if this node is selected
35457 * @return {Boolean}
35459 isSelected : function(){
35460 return this.getOwnerTree().getSelectionModel().isSelected(this);
35464 * Expand this node.
35465 * @param {Boolean} deep (optional) True to expand all children as well
35466 * @param {Boolean} anim (optional) false to cancel the default animation
35467 * @param {Function} callback (optional) A callback to be called when
35468 * expanding this node completes (does not wait for deep expand to complete).
35469 * Called with 1 parameter, this node.
35471 expand : function(deep, anim, callback){
35472 if(!this.expanded){
35473 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35476 if(!this.childrenRendered){
35477 this.renderChildren();
35479 this.expanded = true;
35481 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35482 this.ui.animExpand(function(){
35483 this.fireEvent("expand", this);
35484 if(typeof callback == "function"){
35488 this.expandChildNodes(true);
35490 }.createDelegate(this));
35494 this.fireEvent("expand", this);
35495 if(typeof callback == "function"){
35500 if(typeof callback == "function"){
35505 this.expandChildNodes(true);
35509 isHiddenRoot : function(){
35510 return this.isRoot && !this.getOwnerTree().rootVisible;
35514 * Collapse this node.
35515 * @param {Boolean} deep (optional) True to collapse all children as well
35516 * @param {Boolean} anim (optional) false to cancel the default animation
35518 collapse : function(deep, anim){
35519 if(this.expanded && !this.isHiddenRoot()){
35520 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35523 this.expanded = false;
35524 if((this.getOwnerTree().animate && anim !== false) || anim){
35525 this.ui.animCollapse(function(){
35526 this.fireEvent("collapse", this);
35528 this.collapseChildNodes(true);
35530 }.createDelegate(this));
35533 this.ui.collapse();
35534 this.fireEvent("collapse", this);
35538 var cs = this.childNodes;
35539 for(var i = 0, len = cs.length; i < len; i++) {
35540 cs[i].collapse(true, false);
35546 delayedExpand : function(delay){
35547 if(!this.expandProcId){
35548 this.expandProcId = this.expand.defer(delay, this);
35553 cancelExpand : function(){
35554 if(this.expandProcId){
35555 clearTimeout(this.expandProcId);
35557 this.expandProcId = false;
35561 * Toggles expanded/collapsed state of the node
35563 toggle : function(){
35572 * Ensures all parent nodes are expanded
35574 ensureVisible : function(callback){
35575 var tree = this.getOwnerTree();
35576 tree.expandPath(this.parentNode.getPath(), false, function(){
35577 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35578 Roo.callback(callback);
35579 }.createDelegate(this));
35583 * Expand all child nodes
35584 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35586 expandChildNodes : function(deep){
35587 var cs = this.childNodes;
35588 for(var i = 0, len = cs.length; i < len; i++) {
35589 cs[i].expand(deep);
35594 * Collapse all child nodes
35595 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35597 collapseChildNodes : function(deep){
35598 var cs = this.childNodes;
35599 for(var i = 0, len = cs.length; i < len; i++) {
35600 cs[i].collapse(deep);
35605 * Disables this node
35607 disable : function(){
35608 this.disabled = true;
35610 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35611 this.ui.onDisableChange(this, true);
35613 this.fireEvent("disabledchange", this, true);
35617 * Enables this node
35619 enable : function(){
35620 this.disabled = false;
35621 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35622 this.ui.onDisableChange(this, false);
35624 this.fireEvent("disabledchange", this, false);
35628 renderChildren : function(suppressEvent){
35629 if(suppressEvent !== false){
35630 this.fireEvent("beforechildrenrendered", this);
35632 var cs = this.childNodes;
35633 for(var i = 0, len = cs.length; i < len; i++){
35634 cs[i].render(true);
35636 this.childrenRendered = true;
35640 sort : function(fn, scope){
35641 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35642 if(this.childrenRendered){
35643 var cs = this.childNodes;
35644 for(var i = 0, len = cs.length; i < len; i++){
35645 cs[i].render(true);
35651 render : function(bulkRender){
35652 this.ui.render(bulkRender);
35653 if(!this.rendered){
35654 this.rendered = true;
35656 this.expanded = false;
35657 this.expand(false, false);
35663 renderIndent : function(deep, refresh){
35665 this.ui.childIndent = null;
35667 this.ui.renderIndent();
35668 if(deep === true && this.childrenRendered){
35669 var cs = this.childNodes;
35670 for(var i = 0, len = cs.length; i < len; i++){
35671 cs[i].renderIndent(true, refresh);
35677 * Ext JS Library 1.1.1
35678 * Copyright(c) 2006-2007, Ext JS, LLC.
35680 * Originally Released Under LGPL - original licence link has changed is not relivant.
35683 * <script type="text/javascript">
35687 * @class Roo.tree.AsyncTreeNode
35688 * @extends Roo.tree.TreeNode
35689 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35691 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35693 Roo.tree.AsyncTreeNode = function(config){
35694 this.loaded = false;
35695 this.loading = false;
35696 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35698 * @event beforeload
35699 * Fires before this node is loaded, return false to cancel
35700 * @param {Node} this This node
35702 this.addEvents({'beforeload':true, 'load': true});
35705 * Fires when this node is loaded
35706 * @param {Node} this This node
35709 * The loader used by this node (defaults to using the tree's defined loader)
35714 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35715 expand : function(deep, anim, callback){
35716 if(this.loading){ // if an async load is already running, waiting til it's done
35718 var f = function(){
35719 if(!this.loading){ // done loading
35720 clearInterval(timer);
35721 this.expand(deep, anim, callback);
35723 }.createDelegate(this);
35724 timer = setInterval(f, 200);
35728 if(this.fireEvent("beforeload", this) === false){
35731 this.loading = true;
35732 this.ui.beforeLoad(this);
35733 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35735 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35739 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35743 * Returns true if this node is currently loading
35744 * @return {Boolean}
35746 isLoading : function(){
35747 return this.loading;
35750 loadComplete : function(deep, anim, callback){
35751 this.loading = false;
35752 this.loaded = true;
35753 this.ui.afterLoad(this);
35754 this.fireEvent("load", this);
35755 this.expand(deep, anim, callback);
35759 * Returns true if this node has been loaded
35760 * @return {Boolean}
35762 isLoaded : function(){
35763 return this.loaded;
35766 hasChildNodes : function(){
35767 if(!this.isLeaf() && !this.loaded){
35770 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35775 * Trigger a reload for this node
35776 * @param {Function} callback
35778 reload : function(callback){
35779 this.collapse(false, false);
35780 while(this.firstChild){
35781 this.removeChild(this.firstChild);
35783 this.childrenRendered = false;
35784 this.loaded = false;
35785 if(this.isHiddenRoot()){
35786 this.expanded = false;
35788 this.expand(false, false, callback);
35792 * Ext JS Library 1.1.1
35793 * Copyright(c) 2006-2007, Ext JS, LLC.
35795 * Originally Released Under LGPL - original licence link has changed is not relivant.
35798 * <script type="text/javascript">
35802 * @class Roo.tree.TreeNodeUI
35804 * @param {Object} node The node to render
35805 * The TreeNode UI implementation is separate from the
35806 * tree implementation. Unless you are customizing the tree UI,
35807 * you should never have to use this directly.
35809 Roo.tree.TreeNodeUI = function(node){
35811 this.rendered = false;
35812 this.animating = false;
35813 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35816 Roo.tree.TreeNodeUI.prototype = {
35817 removeChild : function(node){
35819 this.ctNode.removeChild(node.ui.getEl());
35823 beforeLoad : function(){
35824 this.addClass("x-tree-node-loading");
35827 afterLoad : function(){
35828 this.removeClass("x-tree-node-loading");
35831 onTextChange : function(node, text, oldText){
35833 this.textNode.innerHTML = text;
35837 onDisableChange : function(node, state){
35838 this.disabled = state;
35840 this.addClass("x-tree-node-disabled");
35842 this.removeClass("x-tree-node-disabled");
35846 onSelectedChange : function(state){
35849 this.addClass("x-tree-selected");
35852 this.removeClass("x-tree-selected");
35856 onMove : function(tree, node, oldParent, newParent, index, refNode){
35857 this.childIndent = null;
35859 var targetNode = newParent.ui.getContainer();
35860 if(!targetNode){//target not rendered
35861 this.holder = document.createElement("div");
35862 this.holder.appendChild(this.wrap);
35865 var insertBefore = refNode ? refNode.ui.getEl() : null;
35867 targetNode.insertBefore(this.wrap, insertBefore);
35869 targetNode.appendChild(this.wrap);
35871 this.node.renderIndent(true);
35875 addClass : function(cls){
35877 Roo.fly(this.elNode).addClass(cls);
35881 removeClass : function(cls){
35883 Roo.fly(this.elNode).removeClass(cls);
35887 remove : function(){
35889 this.holder = document.createElement("div");
35890 this.holder.appendChild(this.wrap);
35894 fireEvent : function(){
35895 return this.node.fireEvent.apply(this.node, arguments);
35898 initEvents : function(){
35899 this.node.on("move", this.onMove, this);
35900 var E = Roo.EventManager;
35901 var a = this.anchor;
35903 var el = Roo.fly(a, '_treeui');
35905 if(Roo.isOpera){ // opera render bug ignores the CSS
35906 el.setStyle("text-decoration", "none");
35909 el.on("click", this.onClick, this);
35910 el.on("dblclick", this.onDblClick, this);
35913 Roo.EventManager.on(this.checkbox,
35914 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35917 el.on("contextmenu", this.onContextMenu, this);
35919 var icon = Roo.fly(this.iconNode);
35920 icon.on("click", this.onClick, this);
35921 icon.on("dblclick", this.onDblClick, this);
35922 icon.on("contextmenu", this.onContextMenu, this);
35923 E.on(this.ecNode, "click", this.ecClick, this, true);
35925 if(this.node.disabled){
35926 this.addClass("x-tree-node-disabled");
35928 if(this.node.hidden){
35929 this.addClass("x-tree-node-disabled");
35931 var ot = this.node.getOwnerTree();
35932 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35933 if(dd && (!this.node.isRoot || ot.rootVisible)){
35934 Roo.dd.Registry.register(this.elNode, {
35936 handles: this.getDDHandles(),
35942 getDDHandles : function(){
35943 return [this.iconNode, this.textNode];
35948 this.wrap.style.display = "none";
35954 this.wrap.style.display = "";
35958 onContextMenu : function(e){
35959 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35960 e.preventDefault();
35962 this.fireEvent("contextmenu", this.node, e);
35966 onClick : function(e){
35971 if(this.fireEvent("beforeclick", this.node, e) !== false){
35972 if(!this.disabled && this.node.attributes.href){
35973 this.fireEvent("click", this.node, e);
35976 e.preventDefault();
35981 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35982 this.node.toggle();
35985 this.fireEvent("click", this.node, e);
35991 onDblClick : function(e){
35992 e.preventDefault();
35997 this.toggleCheck();
35999 if(!this.animating && this.node.hasChildNodes()){
36000 this.node.toggle();
36002 this.fireEvent("dblclick", this.node, e);
36005 onCheckChange : function(){
36006 var checked = this.checkbox.checked;
36007 this.node.attributes.checked = checked;
36008 this.fireEvent('checkchange', this.node, checked);
36011 ecClick : function(e){
36012 if(!this.animating && this.node.hasChildNodes()){
36013 this.node.toggle();
36017 startDrop : function(){
36018 this.dropping = true;
36021 // delayed drop so the click event doesn't get fired on a drop
36022 endDrop : function(){
36023 setTimeout(function(){
36024 this.dropping = false;
36025 }.createDelegate(this), 50);
36028 expand : function(){
36029 this.updateExpandIcon();
36030 this.ctNode.style.display = "";
36033 focus : function(){
36034 if(!this.node.preventHScroll){
36035 try{this.anchor.focus();
36037 }else if(!Roo.isIE){
36039 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
36040 var l = noscroll.scrollLeft;
36041 this.anchor.focus();
36042 noscroll.scrollLeft = l;
36047 toggleCheck : function(value){
36048 var cb = this.checkbox;
36050 cb.checked = (value === undefined ? !cb.checked : value);
36056 this.anchor.blur();
36060 animExpand : function(callback){
36061 var ct = Roo.get(this.ctNode);
36063 if(!this.node.hasChildNodes()){
36064 this.updateExpandIcon();
36065 this.ctNode.style.display = "";
36066 Roo.callback(callback);
36069 this.animating = true;
36070 this.updateExpandIcon();
36073 callback : function(){
36074 this.animating = false;
36075 Roo.callback(callback);
36078 duration: this.node.ownerTree.duration || .25
36082 highlight : function(){
36083 var tree = this.node.getOwnerTree();
36084 Roo.fly(this.wrap).highlight(
36085 tree.hlColor || "C3DAF9",
36086 {endColor: tree.hlBaseColor}
36090 collapse : function(){
36091 this.updateExpandIcon();
36092 this.ctNode.style.display = "none";
36095 animCollapse : function(callback){
36096 var ct = Roo.get(this.ctNode);
36097 ct.enableDisplayMode('block');
36100 this.animating = true;
36101 this.updateExpandIcon();
36104 callback : function(){
36105 this.animating = false;
36106 Roo.callback(callback);
36109 duration: this.node.ownerTree.duration || .25
36113 getContainer : function(){
36114 return this.ctNode;
36117 getEl : function(){
36121 appendDDGhost : function(ghostNode){
36122 ghostNode.appendChild(this.elNode.cloneNode(true));
36125 getDDRepairXY : function(){
36126 return Roo.lib.Dom.getXY(this.iconNode);
36129 onRender : function(){
36133 render : function(bulkRender){
36134 var n = this.node, a = n.attributes;
36135 var targetNode = n.parentNode ?
36136 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
36138 if(!this.rendered){
36139 this.rendered = true;
36141 this.renderElements(n, a, targetNode, bulkRender);
36144 if(this.textNode.setAttributeNS){
36145 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
36147 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
36150 this.textNode.setAttribute("ext:qtip", a.qtip);
36152 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
36155 }else if(a.qtipCfg){
36156 a.qtipCfg.target = Roo.id(this.textNode);
36157 Roo.QuickTips.register(a.qtipCfg);
36160 if(!this.node.expanded){
36161 this.updateExpandIcon();
36164 if(bulkRender === true) {
36165 targetNode.appendChild(this.wrap);
36170 renderElements : function(n, a, targetNode, bulkRender)
36172 // add some indent caching, this helps performance when rendering a large tree
36173 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36174 var t = n.getOwnerTree();
36175 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36176 if (typeof(n.attributes.html) != 'undefined') {
36177 txt = n.attributes.html;
36179 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36180 var cb = typeof a.checked == 'boolean';
36181 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36182 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36183 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36184 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36185 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
36186 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
36187 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
36188 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
36189 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
36190 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36193 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36194 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36195 n.nextSibling.ui.getEl(), buf.join(""));
36197 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36200 this.elNode = this.wrap.childNodes[0];
36201 this.ctNode = this.wrap.childNodes[1];
36202 var cs = this.elNode.childNodes;
36203 this.indentNode = cs[0];
36204 this.ecNode = cs[1];
36205 this.iconNode = cs[2];
36208 this.checkbox = cs[3];
36211 this.anchor = cs[index];
36212 this.textNode = cs[index].firstChild;
36215 getAnchor : function(){
36216 return this.anchor;
36219 getTextEl : function(){
36220 return this.textNode;
36223 getIconEl : function(){
36224 return this.iconNode;
36227 isChecked : function(){
36228 return this.checkbox ? this.checkbox.checked : false;
36231 updateExpandIcon : function(){
36233 var n = this.node, c1, c2;
36234 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36235 var hasChild = n.hasChildNodes();
36239 c1 = "x-tree-node-collapsed";
36240 c2 = "x-tree-node-expanded";
36243 c1 = "x-tree-node-expanded";
36244 c2 = "x-tree-node-collapsed";
36247 this.removeClass("x-tree-node-leaf");
36248 this.wasLeaf = false;
36250 if(this.c1 != c1 || this.c2 != c2){
36251 Roo.fly(this.elNode).replaceClass(c1, c2);
36252 this.c1 = c1; this.c2 = c2;
36255 // this changes non-leafs into leafs if they have no children.
36256 // it's not very rational behaviour..
36258 if(!this.wasLeaf && this.node.leaf){
36259 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36262 this.wasLeaf = true;
36265 var ecc = "x-tree-ec-icon "+cls;
36266 if(this.ecc != ecc){
36267 this.ecNode.className = ecc;
36273 getChildIndent : function(){
36274 if(!this.childIndent){
36278 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36280 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36282 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36287 this.childIndent = buf.join("");
36289 return this.childIndent;
36292 renderIndent : function(){
36295 var p = this.node.parentNode;
36297 indent = p.ui.getChildIndent();
36299 if(this.indentMarkup != indent){ // don't rerender if not required
36300 this.indentNode.innerHTML = indent;
36301 this.indentMarkup = indent;
36303 this.updateExpandIcon();
36308 Roo.tree.RootTreeNodeUI = function(){
36309 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36311 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36312 render : function(){
36313 if(!this.rendered){
36314 var targetNode = this.node.ownerTree.innerCt.dom;
36315 this.node.expanded = true;
36316 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36317 this.wrap = this.ctNode = targetNode.firstChild;
36320 collapse : function(){
36322 expand : function(){
36326 * Ext JS Library 1.1.1
36327 * Copyright(c) 2006-2007, Ext JS, LLC.
36329 * Originally Released Under LGPL - original licence link has changed is not relivant.
36332 * <script type="text/javascript">
36335 * @class Roo.tree.TreeLoader
36336 * @extends Roo.util.Observable
36337 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36338 * nodes from a specified URL. The response must be a javascript Array definition
36339 * who's elements are node definition objects. eg:
36344 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36345 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36352 * The old style respose with just an array is still supported, but not recommended.
36355 * A server request is sent, and child nodes are loaded only when a node is expanded.
36356 * The loading node's id is passed to the server under the parameter name "node" to
36357 * enable the server to produce the correct child nodes.
36359 * To pass extra parameters, an event handler may be attached to the "beforeload"
36360 * event, and the parameters specified in the TreeLoader's baseParams property:
36362 myTreeLoader.on("beforeload", function(treeLoader, node) {
36363 this.baseParams.category = node.attributes.category;
36368 * This would pass an HTTP parameter called "category" to the server containing
36369 * the value of the Node's "category" attribute.
36371 * Creates a new Treeloader.
36372 * @param {Object} config A config object containing config properties.
36374 Roo.tree.TreeLoader = function(config){
36375 this.baseParams = {};
36376 this.requestMethod = "POST";
36377 Roo.apply(this, config);
36382 * @event beforeload
36383 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36384 * @param {Object} This TreeLoader object.
36385 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36386 * @param {Object} callback The callback function specified in the {@link #load} call.
36391 * Fires when the node has been successfuly loaded.
36392 * @param {Object} This TreeLoader object.
36393 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36394 * @param {Object} response The response object containing the data from the server.
36398 * @event loadexception
36399 * Fires if the network request failed.
36400 * @param {Object} This TreeLoader object.
36401 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36402 * @param {Object} response The response object containing the data from the server.
36404 loadexception : true,
36407 * Fires before a node is created, enabling you to return custom Node types
36408 * @param {Object} This TreeLoader object.
36409 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36414 Roo.tree.TreeLoader.superclass.constructor.call(this);
36417 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36419 * @cfg {String} dataUrl The URL from which to request a Json string which
36420 * specifies an array of node definition object representing the child nodes
36424 * @cfg {String} requestMethod either GET or POST
36425 * defaults to POST (due to BC)
36429 * @cfg {Object} baseParams (optional) An object containing properties which
36430 * specify HTTP parameters to be passed to each request for child nodes.
36433 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36434 * created by this loader. If the attributes sent by the server have an attribute in this object,
36435 * they take priority.
36438 * @cfg {Object} uiProviders (optional) An object containing properties which
36440 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36441 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36442 * <i>uiProvider</i> attribute of a returned child node is a string rather
36443 * than a reference to a TreeNodeUI implementation, this that string value
36444 * is used as a property name in the uiProviders object. You can define the provider named
36445 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36450 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36451 * child nodes before loading.
36453 clearOnLoad : true,
36456 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36457 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36458 * Grid query { data : [ .....] }
36463 * @cfg {String} queryParam (optional)
36464 * Name of the query as it will be passed on the querystring (defaults to 'node')
36465 * eg. the request will be ?node=[id]
36472 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36473 * This is called automatically when a node is expanded, but may be used to reload
36474 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36475 * @param {Roo.tree.TreeNode} node
36476 * @param {Function} callback
36478 load : function(node, callback){
36479 if(this.clearOnLoad){
36480 while(node.firstChild){
36481 node.removeChild(node.firstChild);
36484 if(node.attributes.children){ // preloaded json children
36485 var cs = node.attributes.children;
36486 for(var i = 0, len = cs.length; i < len; i++){
36487 node.appendChild(this.createNode(cs[i]));
36489 if(typeof callback == "function"){
36492 }else if(this.dataUrl){
36493 this.requestData(node, callback);
36497 getParams: function(node){
36498 var buf = [], bp = this.baseParams;
36499 for(var key in bp){
36500 if(typeof bp[key] != "function"){
36501 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36504 var n = this.queryParam === false ? 'node' : this.queryParam;
36505 buf.push(n + "=", encodeURIComponent(node.id));
36506 return buf.join("");
36509 requestData : function(node, callback){
36510 if(this.fireEvent("beforeload", this, node, callback) !== false){
36511 this.transId = Roo.Ajax.request({
36512 method:this.requestMethod,
36513 url: this.dataUrl||this.url,
36514 success: this.handleResponse,
36515 failure: this.handleFailure,
36517 argument: {callback: callback, node: node},
36518 params: this.getParams(node)
36521 // if the load is cancelled, make sure we notify
36522 // the node that we are done
36523 if(typeof callback == "function"){
36529 isLoading : function(){
36530 return this.transId ? true : false;
36533 abort : function(){
36534 if(this.isLoading()){
36535 Roo.Ajax.abort(this.transId);
36540 createNode : function(attr)
36542 // apply baseAttrs, nice idea Corey!
36543 if(this.baseAttrs){
36544 Roo.applyIf(attr, this.baseAttrs);
36546 if(this.applyLoader !== false){
36547 attr.loader = this;
36549 // uiProvider = depreciated..
36551 if(typeof(attr.uiProvider) == 'string'){
36552 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36553 /** eval:var:attr */ eval(attr.uiProvider);
36555 if(typeof(this.uiProviders['default']) != 'undefined') {
36556 attr.uiProvider = this.uiProviders['default'];
36559 this.fireEvent('create', this, attr);
36561 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36563 new Roo.tree.TreeNode(attr) :
36564 new Roo.tree.AsyncTreeNode(attr));
36567 processResponse : function(response, node, callback)
36569 var json = response.responseText;
36572 var o = Roo.decode(json);
36574 if (this.root === false && typeof(o.success) != undefined) {
36575 this.root = 'data'; // the default behaviour for list like data..
36578 if (this.root !== false && !o.success) {
36579 // it's a failure condition.
36580 var a = response.argument;
36581 this.fireEvent("loadexception", this, a.node, response);
36582 Roo.log("Load failed - should have a handler really");
36588 if (this.root !== false) {
36592 for(var i = 0, len = o.length; i < len; i++){
36593 var n = this.createNode(o[i]);
36595 node.appendChild(n);
36598 if(typeof callback == "function"){
36599 callback(this, node);
36602 this.handleFailure(response);
36606 handleResponse : function(response){
36607 this.transId = false;
36608 var a = response.argument;
36609 this.processResponse(response, a.node, a.callback);
36610 this.fireEvent("load", this, a.node, response);
36613 handleFailure : function(response)
36615 // should handle failure better..
36616 this.transId = false;
36617 var a = response.argument;
36618 this.fireEvent("loadexception", this, a.node, response);
36619 if(typeof a.callback == "function"){
36620 a.callback(this, a.node);
36625 * Ext JS Library 1.1.1
36626 * Copyright(c) 2006-2007, Ext JS, LLC.
36628 * Originally Released Under LGPL - original licence link has changed is not relivant.
36631 * <script type="text/javascript">
36635 * @class Roo.tree.TreeFilter
36636 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36637 * @param {TreePanel} tree
36638 * @param {Object} config (optional)
36640 Roo.tree.TreeFilter = function(tree, config){
36642 this.filtered = {};
36643 Roo.apply(this, config);
36646 Roo.tree.TreeFilter.prototype = {
36653 * Filter the data by a specific attribute.
36654 * @param {String/RegExp} value Either string that the attribute value
36655 * should start with or a RegExp to test against the attribute
36656 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36657 * @param {TreeNode} startNode (optional) The node to start the filter at.
36659 filter : function(value, attr, startNode){
36660 attr = attr || "text";
36662 if(typeof value == "string"){
36663 var vlen = value.length;
36664 // auto clear empty filter
36665 if(vlen == 0 && this.clearBlank){
36669 value = value.toLowerCase();
36671 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36673 }else if(value.exec){ // regex?
36675 return value.test(n.attributes[attr]);
36678 throw 'Illegal filter type, must be string or regex';
36680 this.filterBy(f, null, startNode);
36684 * Filter by a function. The passed function will be called with each
36685 * node in the tree (or from the startNode). If the function returns true, the node is kept
36686 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36687 * @param {Function} fn The filter function
36688 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36690 filterBy : function(fn, scope, startNode){
36691 startNode = startNode || this.tree.root;
36692 if(this.autoClear){
36695 var af = this.filtered, rv = this.reverse;
36696 var f = function(n){
36697 if(n == startNode){
36703 var m = fn.call(scope || n, n);
36711 startNode.cascade(f);
36714 if(typeof id != "function"){
36716 if(n && n.parentNode){
36717 n.parentNode.removeChild(n);
36725 * Clears the current filter. Note: with the "remove" option
36726 * set a filter cannot be cleared.
36728 clear : function(){
36730 var af = this.filtered;
36732 if(typeof id != "function"){
36739 this.filtered = {};
36744 * Ext JS Library 1.1.1
36745 * Copyright(c) 2006-2007, Ext JS, LLC.
36747 * Originally Released Under LGPL - original licence link has changed is not relivant.
36750 * <script type="text/javascript">
36755 * @class Roo.tree.TreeSorter
36756 * Provides sorting of nodes in a TreePanel
36758 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36759 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36760 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36761 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36762 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36763 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36765 * @param {TreePanel} tree
36766 * @param {Object} config
36768 Roo.tree.TreeSorter = function(tree, config){
36769 Roo.apply(this, config);
36770 tree.on("beforechildrenrendered", this.doSort, this);
36771 tree.on("append", this.updateSort, this);
36772 tree.on("insert", this.updateSort, this);
36774 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36775 var p = this.property || "text";
36776 var sortType = this.sortType;
36777 var fs = this.folderSort;
36778 var cs = this.caseSensitive === true;
36779 var leafAttr = this.leafAttr || 'leaf';
36781 this.sortFn = function(n1, n2){
36783 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36786 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36790 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36791 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36793 return dsc ? +1 : -1;
36795 return dsc ? -1 : +1;
36802 Roo.tree.TreeSorter.prototype = {
36803 doSort : function(node){
36804 node.sort(this.sortFn);
36807 compareNodes : function(n1, n2){
36808 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36811 updateSort : function(tree, node){
36812 if(node.childrenRendered){
36813 this.doSort.defer(1, this, [node]);
36818 * Ext JS Library 1.1.1
36819 * Copyright(c) 2006-2007, Ext JS, LLC.
36821 * Originally Released Under LGPL - original licence link has changed is not relivant.
36824 * <script type="text/javascript">
36827 if(Roo.dd.DropZone){
36829 Roo.tree.TreeDropZone = function(tree, config){
36830 this.allowParentInsert = false;
36831 this.allowContainerDrop = false;
36832 this.appendOnly = false;
36833 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36835 this.lastInsertClass = "x-tree-no-status";
36836 this.dragOverData = {};
36839 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36840 ddGroup : "TreeDD",
36843 expandDelay : 1000,
36845 expandNode : function(node){
36846 if(node.hasChildNodes() && !node.isExpanded()){
36847 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36851 queueExpand : function(node){
36852 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36855 cancelExpand : function(){
36856 if(this.expandProcId){
36857 clearTimeout(this.expandProcId);
36858 this.expandProcId = false;
36862 isValidDropPoint : function(n, pt, dd, e, data){
36863 if(!n || !data){ return false; }
36864 var targetNode = n.node;
36865 var dropNode = data.node;
36866 // default drop rules
36867 if(!(targetNode && targetNode.isTarget && pt)){
36870 if(pt == "append" && targetNode.allowChildren === false){
36873 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36876 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36879 // reuse the object
36880 var overEvent = this.dragOverData;
36881 overEvent.tree = this.tree;
36882 overEvent.target = targetNode;
36883 overEvent.data = data;
36884 overEvent.point = pt;
36885 overEvent.source = dd;
36886 overEvent.rawEvent = e;
36887 overEvent.dropNode = dropNode;
36888 overEvent.cancel = false;
36889 var result = this.tree.fireEvent("nodedragover", overEvent);
36890 return overEvent.cancel === false && result !== false;
36893 getDropPoint : function(e, n, dd)
36897 return tn.allowChildren !== false ? "append" : false; // always append for root
36899 var dragEl = n.ddel;
36900 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36901 var y = Roo.lib.Event.getPageY(e);
36902 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36904 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36905 var noAppend = tn.allowChildren === false;
36906 if(this.appendOnly || tn.parentNode.allowChildren === false){
36907 return noAppend ? false : "append";
36909 var noBelow = false;
36910 if(!this.allowParentInsert){
36911 noBelow = tn.hasChildNodes() && tn.isExpanded();
36913 var q = (b - t) / (noAppend ? 2 : 3);
36914 if(y >= t && y < (t + q)){
36916 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36923 onNodeEnter : function(n, dd, e, data)
36925 this.cancelExpand();
36928 onNodeOver : function(n, dd, e, data)
36931 var pt = this.getDropPoint(e, n, dd);
36934 // auto node expand check
36935 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36936 this.queueExpand(node);
36937 }else if(pt != "append"){
36938 this.cancelExpand();
36941 // set the insert point style on the target node
36942 var returnCls = this.dropNotAllowed;
36943 if(this.isValidDropPoint(n, pt, dd, e, data)){
36948 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36949 cls = "x-tree-drag-insert-above";
36950 }else if(pt == "below"){
36951 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36952 cls = "x-tree-drag-insert-below";
36954 returnCls = "x-tree-drop-ok-append";
36955 cls = "x-tree-drag-append";
36957 if(this.lastInsertClass != cls){
36958 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36959 this.lastInsertClass = cls;
36966 onNodeOut : function(n, dd, e, data){
36968 this.cancelExpand();
36969 this.removeDropIndicators(n);
36972 onNodeDrop : function(n, dd, e, data){
36973 var point = this.getDropPoint(e, n, dd);
36974 var targetNode = n.node;
36975 targetNode.ui.startDrop();
36976 if(!this.isValidDropPoint(n, point, dd, e, data)){
36977 targetNode.ui.endDrop();
36980 // first try to find the drop node
36981 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36984 target: targetNode,
36989 dropNode: dropNode,
36992 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36993 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36994 targetNode.ui.endDrop();
36997 // allow target changing
36998 targetNode = dropEvent.target;
36999 if(point == "append" && !targetNode.isExpanded()){
37000 targetNode.expand(false, null, function(){
37001 this.completeDrop(dropEvent);
37002 }.createDelegate(this));
37004 this.completeDrop(dropEvent);
37009 completeDrop : function(de){
37010 var ns = de.dropNode, p = de.point, t = de.target;
37011 if(!(ns instanceof Array)){
37015 for(var i = 0, len = ns.length; i < len; i++){
37018 t.parentNode.insertBefore(n, t);
37019 }else if(p == "below"){
37020 t.parentNode.insertBefore(n, t.nextSibling);
37026 if(this.tree.hlDrop){
37030 this.tree.fireEvent("nodedrop", de);
37033 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
37034 if(this.tree.hlDrop){
37035 dropNode.ui.focus();
37036 dropNode.ui.highlight();
37038 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
37041 getTree : function(){
37045 removeDropIndicators : function(n){
37048 Roo.fly(el).removeClass([
37049 "x-tree-drag-insert-above",
37050 "x-tree-drag-insert-below",
37051 "x-tree-drag-append"]);
37052 this.lastInsertClass = "_noclass";
37056 beforeDragDrop : function(target, e, id){
37057 this.cancelExpand();
37061 afterRepair : function(data){
37062 if(data && Roo.enableFx){
37063 data.node.ui.highlight();
37073 * Ext JS Library 1.1.1
37074 * Copyright(c) 2006-2007, Ext JS, LLC.
37076 * Originally Released Under LGPL - original licence link has changed is not relivant.
37079 * <script type="text/javascript">
37083 if(Roo.dd.DragZone){
37084 Roo.tree.TreeDragZone = function(tree, config){
37085 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
37089 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
37090 ddGroup : "TreeDD",
37092 onBeforeDrag : function(data, e){
37094 return n && n.draggable && !n.disabled;
37098 onInitDrag : function(e){
37099 var data = this.dragData;
37100 this.tree.getSelectionModel().select(data.node);
37101 this.proxy.update("");
37102 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
37103 this.tree.fireEvent("startdrag", this.tree, data.node, e);
37106 getRepairXY : function(e, data){
37107 return data.node.ui.getDDRepairXY();
37110 onEndDrag : function(data, e){
37111 this.tree.fireEvent("enddrag", this.tree, data.node, e);
37116 onValidDrop : function(dd, e, id){
37117 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
37121 beforeInvalidDrop : function(e, id){
37122 // this scrolls the original position back into view
37123 var sm = this.tree.getSelectionModel();
37124 sm.clearSelections();
37125 sm.select(this.dragData.node);
37130 * Ext JS Library 1.1.1
37131 * Copyright(c) 2006-2007, Ext JS, LLC.
37133 * Originally Released Under LGPL - original licence link has changed is not relivant.
37136 * <script type="text/javascript">
37139 * @class Roo.tree.TreeEditor
37140 * @extends Roo.Editor
37141 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
37142 * as the editor field.
37144 * @param {Object} config (used to be the tree panel.)
37145 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
37147 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
37148 * @cfg {Roo.form.TextField} field [required] The field configuration
37152 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
37155 if (oldconfig) { // old style..
37156 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
37159 tree = config.tree;
37160 config.field = config.field || {};
37161 config.field.xtype = 'TextField';
37162 field = Roo.factory(config.field, Roo.form);
37164 config = config || {};
37169 * @event beforenodeedit
37170 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37171 * false from the handler of this event.
37172 * @param {Editor} this
37173 * @param {Roo.tree.Node} node
37175 "beforenodeedit" : true
37179 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37183 tree.on('beforeclick', this.beforeNodeClick, this);
37184 tree.getTreeEl().on('mousedown', this.hide, this);
37185 this.on('complete', this.updateNode, this);
37186 this.on('beforestartedit', this.fitToTree, this);
37187 this.on('startedit', this.bindScroll, this, {delay:10});
37188 this.on('specialkey', this.onSpecialKey, this);
37191 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
37193 * @cfg {String} alignment
37194 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37200 * @cfg {Boolean} hideEl
37201 * True to hide the bound element while the editor is displayed (defaults to false)
37205 * @cfg {String} cls
37206 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37208 cls: "x-small-editor x-tree-editor",
37210 * @cfg {Boolean} shim
37211 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37217 * @cfg {Number} maxWidth
37218 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37219 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37220 * scroll and client offsets into account prior to each edit.
37227 fitToTree : function(ed, el){
37228 var td = this.tree.getTreeEl().dom, nd = el.dom;
37229 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37230 td.scrollLeft = nd.offsetLeft;
37234 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37235 this.setSize(w, '');
37237 return this.fireEvent('beforenodeedit', this, this.editNode);
37242 triggerEdit : function(node){
37243 this.completeEdit();
37244 this.editNode = node;
37245 this.startEdit(node.ui.textNode, node.text);
37249 bindScroll : function(){
37250 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37254 beforeNodeClick : function(node, e){
37255 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37256 this.lastClick = new Date();
37257 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37259 this.triggerEdit(node);
37266 updateNode : function(ed, value){
37267 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37268 this.editNode.setText(value);
37272 onHide : function(){
37273 Roo.tree.TreeEditor.superclass.onHide.call(this);
37275 this.editNode.ui.focus();
37280 onSpecialKey : function(field, e){
37281 var k = e.getKey();
37285 }else if(k == e.ENTER && !e.hasModifier()){
37287 this.completeEdit();
37290 });//<Script type="text/javascript">
37293 * Ext JS Library 1.1.1
37294 * Copyright(c) 2006-2007, Ext JS, LLC.
37296 * Originally Released Under LGPL - original licence link has changed is not relivant.
37299 * <script type="text/javascript">
37303 * Not documented??? - probably should be...
37306 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37307 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37309 renderElements : function(n, a, targetNode, bulkRender){
37310 //consel.log("renderElements?");
37311 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37313 var t = n.getOwnerTree();
37314 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37316 var cols = t.columns;
37317 var bw = t.borderWidth;
37319 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37320 var cb = typeof a.checked == "boolean";
37321 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37322 var colcls = 'x-t-' + tid + '-c0';
37324 '<li class="x-tree-node">',
37327 '<div class="x-tree-node-el ', a.cls,'">',
37329 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37332 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37333 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37334 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37335 (a.icon ? ' x-tree-node-inline-icon' : ''),
37336 (a.iconCls ? ' '+a.iconCls : ''),
37337 '" unselectable="on" />',
37338 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37339 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37341 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37342 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37343 '<span unselectable="on" qtip="' + tx + '">',
37347 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37348 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37350 for(var i = 1, len = cols.length; i < len; i++){
37352 colcls = 'x-t-' + tid + '-c' +i;
37353 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37354 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37355 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37361 '<div class="x-clear"></div></div>',
37362 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37365 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37366 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37367 n.nextSibling.ui.getEl(), buf.join(""));
37369 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37371 var el = this.wrap.firstChild;
37373 this.elNode = el.firstChild;
37374 this.ranchor = el.childNodes[1];
37375 this.ctNode = this.wrap.childNodes[1];
37376 var cs = el.firstChild.childNodes;
37377 this.indentNode = cs[0];
37378 this.ecNode = cs[1];
37379 this.iconNode = cs[2];
37382 this.checkbox = cs[3];
37385 this.anchor = cs[index];
37387 this.textNode = cs[index].firstChild;
37389 //el.on("click", this.onClick, this);
37390 //el.on("dblclick", this.onDblClick, this);
37393 // console.log(this);
37395 initEvents : function(){
37396 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37399 var a = this.ranchor;
37401 var el = Roo.get(a);
37403 if(Roo.isOpera){ // opera render bug ignores the CSS
37404 el.setStyle("text-decoration", "none");
37407 el.on("click", this.onClick, this);
37408 el.on("dblclick", this.onDblClick, this);
37409 el.on("contextmenu", this.onContextMenu, this);
37413 /*onSelectedChange : function(state){
37416 this.addClass("x-tree-selected");
37419 this.removeClass("x-tree-selected");
37422 addClass : function(cls){
37424 Roo.fly(this.elRow).addClass(cls);
37430 removeClass : function(cls){
37432 Roo.fly(this.elRow).removeClass(cls);
37438 });//<Script type="text/javascript">
37442 * Ext JS Library 1.1.1
37443 * Copyright(c) 2006-2007, Ext JS, LLC.
37445 * Originally Released Under LGPL - original licence link has changed is not relivant.
37448 * <script type="text/javascript">
37453 * @class Roo.tree.ColumnTree
37454 * @extends Roo.tree.TreePanel
37455 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37456 * @cfg {int} borderWidth compined right/left border allowance
37458 * @param {String/HTMLElement/Element} el The container element
37459 * @param {Object} config
37461 Roo.tree.ColumnTree = function(el, config)
37463 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37467 * Fire this event on a container when it resizes
37468 * @param {int} w Width
37469 * @param {int} h Height
37473 this.on('resize', this.onResize, this);
37476 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37480 borderWidth: Roo.isBorderBox ? 0 : 2,
37483 render : function(){
37484 // add the header.....
37486 Roo.tree.ColumnTree.superclass.render.apply(this);
37488 this.el.addClass('x-column-tree');
37490 this.headers = this.el.createChild(
37491 {cls:'x-tree-headers'},this.innerCt.dom);
37493 var cols = this.columns, c;
37494 var totalWidth = 0;
37496 var len = cols.length;
37497 for(var i = 0; i < len; i++){
37499 totalWidth += c.width;
37500 this.headEls.push(this.headers.createChild({
37501 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37503 cls:'x-tree-hd-text',
37506 style:'width:'+(c.width-this.borderWidth)+'px;'
37509 this.headers.createChild({cls:'x-clear'});
37510 // prevent floats from wrapping when clipped
37511 this.headers.setWidth(totalWidth);
37512 //this.innerCt.setWidth(totalWidth);
37513 this.innerCt.setStyle({ overflow: 'auto' });
37514 this.onResize(this.width, this.height);
37518 onResize : function(w,h)
37523 this.innerCt.setWidth(this.width);
37524 this.innerCt.setHeight(this.height-20);
37527 var cols = this.columns, c;
37528 var totalWidth = 0;
37530 var len = cols.length;
37531 for(var i = 0; i < len; i++){
37533 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37534 // it's the expander..
37535 expEl = this.headEls[i];
37538 totalWidth += c.width;
37542 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37544 this.headers.setWidth(w-20);
37553 * Ext JS Library 1.1.1
37554 * Copyright(c) 2006-2007, Ext JS, LLC.
37556 * Originally Released Under LGPL - original licence link has changed is not relivant.
37559 * <script type="text/javascript">
37563 * @class Roo.menu.Menu
37564 * @extends Roo.util.Observable
37565 * @children Roo.menu.BaseItem
37566 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37567 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37569 * Creates a new Menu
37570 * @param {Object} config Configuration options
37572 Roo.menu.Menu = function(config){
37574 Roo.menu.Menu.superclass.constructor.call(this, config);
37576 this.id = this.id || Roo.id();
37579 * @event beforeshow
37580 * Fires before this menu is displayed
37581 * @param {Roo.menu.Menu} this
37585 * @event beforehide
37586 * Fires before this menu is hidden
37587 * @param {Roo.menu.Menu} this
37592 * Fires after this menu is displayed
37593 * @param {Roo.menu.Menu} this
37598 * Fires after this menu is hidden
37599 * @param {Roo.menu.Menu} this
37604 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37605 * @param {Roo.menu.Menu} this
37606 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37607 * @param {Roo.EventObject} e
37612 * Fires when the mouse is hovering over this menu
37613 * @param {Roo.menu.Menu} this
37614 * @param {Roo.EventObject} e
37615 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37620 * Fires when the mouse exits this menu
37621 * @param {Roo.menu.Menu} this
37622 * @param {Roo.EventObject} e
37623 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37628 * Fires when a menu item contained in this menu is clicked
37629 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37630 * @param {Roo.EventObject} e
37634 if (this.registerMenu) {
37635 Roo.menu.MenuMgr.register(this);
37638 var mis = this.items;
37639 this.items = new Roo.util.MixedCollection();
37641 this.add.apply(this, mis);
37645 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37647 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37651 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37652 * for bottom-right shadow (defaults to "sides")
37656 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37657 * this menu (defaults to "tl-tr?")
37659 subMenuAlign : "tl-tr?",
37661 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37662 * relative to its element of origin (defaults to "tl-bl?")
37664 defaultAlign : "tl-bl?",
37666 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37668 allowOtherMenus : false,
37670 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37672 registerMenu : true,
37677 render : function(){
37681 var el = this.el = new Roo.Layer({
37683 shadow:this.shadow,
37685 parentEl: this.parentEl || document.body,
37689 this.keyNav = new Roo.menu.MenuNav(this);
37692 el.addClass("x-menu-plain");
37695 el.addClass(this.cls);
37697 // generic focus element
37698 this.focusEl = el.createChild({
37699 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37701 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37702 //disabling touch- as it's causing issues ..
37703 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37704 ul.on('click' , this.onClick, this);
37707 ul.on("mouseover", this.onMouseOver, this);
37708 ul.on("mouseout", this.onMouseOut, this);
37709 this.items.each(function(item){
37714 var li = document.createElement("li");
37715 li.className = "x-menu-list-item";
37716 ul.dom.appendChild(li);
37717 item.render(li, this);
37724 autoWidth : function(){
37725 var el = this.el, ul = this.ul;
37729 var w = this.width;
37732 }else if(Roo.isIE){
37733 el.setWidth(this.minWidth);
37734 var t = el.dom.offsetWidth; // force recalc
37735 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37740 delayAutoWidth : function(){
37743 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37745 this.awTask.delay(20);
37750 findTargetItem : function(e){
37751 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37752 if(t && t.menuItemId){
37753 return this.items.get(t.menuItemId);
37758 onClick : function(e){
37759 Roo.log("menu.onClick");
37760 var t = this.findTargetItem(e);
37765 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37766 if(t == this.activeItem && t.shouldDeactivate(e)){
37767 this.activeItem.deactivate();
37768 delete this.activeItem;
37772 this.setActiveItem(t, true);
37780 this.fireEvent("click", this, t, e);
37784 setActiveItem : function(item, autoExpand){
37785 if(item != this.activeItem){
37786 if(this.activeItem){
37787 this.activeItem.deactivate();
37789 this.activeItem = item;
37790 item.activate(autoExpand);
37791 }else if(autoExpand){
37797 tryActivate : function(start, step){
37798 var items = this.items;
37799 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37800 var item = items.get(i);
37801 if(!item.disabled && item.canActivate){
37802 this.setActiveItem(item, false);
37810 onMouseOver : function(e){
37812 if(t = this.findTargetItem(e)){
37813 if(t.canActivate && !t.disabled){
37814 this.setActiveItem(t, true);
37817 this.fireEvent("mouseover", this, e, t);
37821 onMouseOut : function(e){
37823 if(t = this.findTargetItem(e)){
37824 if(t == this.activeItem && t.shouldDeactivate(e)){
37825 this.activeItem.deactivate();
37826 delete this.activeItem;
37829 this.fireEvent("mouseout", this, e, t);
37833 * Read-only. Returns true if the menu is currently displayed, else false.
37836 isVisible : function(){
37837 return this.el && !this.hidden;
37841 * Displays this menu relative to another element
37842 * @param {String/HTMLElement/Roo.Element} element The element to align to
37843 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37844 * the element (defaults to this.defaultAlign)
37845 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37847 show : function(el, pos, parentMenu){
37848 this.parentMenu = parentMenu;
37852 this.fireEvent("beforeshow", this);
37853 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37857 * Displays this menu at a specific xy position
37858 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37859 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37861 showAt : function(xy, parentMenu, /* private: */_e){
37862 this.parentMenu = parentMenu;
37867 this.fireEvent("beforeshow", this);
37868 xy = this.el.adjustForConstraints(xy);
37872 this.hidden = false;
37874 this.fireEvent("show", this);
37877 focus : function(){
37879 this.doFocus.defer(50, this);
37883 doFocus : function(){
37885 this.focusEl.focus();
37890 * Hides this menu and optionally all parent menus
37891 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37893 hide : function(deep){
37894 if(this.el && this.isVisible()){
37895 this.fireEvent("beforehide", this);
37896 if(this.activeItem){
37897 this.activeItem.deactivate();
37898 this.activeItem = null;
37901 this.hidden = true;
37902 this.fireEvent("hide", this);
37904 if(deep === true && this.parentMenu){
37905 this.parentMenu.hide(true);
37910 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37911 * Any of the following are valid:
37913 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37914 * <li>An HTMLElement object which will be converted to a menu item</li>
37915 * <li>A menu item config object that will be created as a new menu item</li>
37916 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37917 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37922 var menu = new Roo.menu.Menu();
37924 // Create a menu item to add by reference
37925 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37927 // Add a bunch of items at once using different methods.
37928 // Only the last item added will be returned.
37929 var item = menu.add(
37930 menuItem, // add existing item by ref
37931 'Dynamic Item', // new TextItem
37932 '-', // new separator
37933 { text: 'Config Item' } // new item by config
37936 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37937 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37940 var a = arguments, l = a.length, item;
37941 for(var i = 0; i < l; i++){
37943 if ((typeof(el) == "object") && el.xtype && el.xns) {
37944 el = Roo.factory(el, Roo.menu);
37947 if(el.render){ // some kind of Item
37948 item = this.addItem(el);
37949 }else if(typeof el == "string"){ // string
37950 if(el == "separator" || el == "-"){
37951 item = this.addSeparator();
37953 item = this.addText(el);
37955 }else if(el.tagName || el.el){ // element
37956 item = this.addElement(el);
37957 }else if(typeof el == "object"){ // must be menu item config?
37958 item = this.addMenuItem(el);
37965 * Returns this menu's underlying {@link Roo.Element} object
37966 * @return {Roo.Element} The element
37968 getEl : function(){
37976 * Adds a separator bar to the menu
37977 * @return {Roo.menu.Item} The menu item that was added
37979 addSeparator : function(){
37980 return this.addItem(new Roo.menu.Separator());
37984 * Adds an {@link Roo.Element} object to the menu
37985 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37986 * @return {Roo.menu.Item} The menu item that was added
37988 addElement : function(el){
37989 return this.addItem(new Roo.menu.BaseItem(el));
37993 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37994 * @param {Roo.menu.Item} item The menu item to add
37995 * @return {Roo.menu.Item} The menu item that was added
37997 addItem : function(item){
37998 this.items.add(item);
38000 var li = document.createElement("li");
38001 li.className = "x-menu-list-item";
38002 this.ul.dom.appendChild(li);
38003 item.render(li, this);
38004 this.delayAutoWidth();
38010 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
38011 * @param {Object} config A MenuItem config object
38012 * @return {Roo.menu.Item} The menu item that was added
38014 addMenuItem : function(config){
38015 if(!(config instanceof Roo.menu.Item)){
38016 if(typeof config.checked == "boolean"){ // must be check menu item config?
38017 config = new Roo.menu.CheckItem(config);
38019 config = new Roo.menu.Item(config);
38022 return this.addItem(config);
38026 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
38027 * @param {String} text The text to display in the menu item
38028 * @return {Roo.menu.Item} The menu item that was added
38030 addText : function(text){
38031 return this.addItem(new Roo.menu.TextItem({ text : text }));
38035 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
38036 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
38037 * @param {Roo.menu.Item} item The menu item to add
38038 * @return {Roo.menu.Item} The menu item that was added
38040 insert : function(index, item){
38041 this.items.insert(index, item);
38043 var li = document.createElement("li");
38044 li.className = "x-menu-list-item";
38045 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
38046 item.render(li, this);
38047 this.delayAutoWidth();
38053 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
38054 * @param {Roo.menu.Item} item The menu item to remove
38056 remove : function(item){
38057 this.items.removeKey(item.id);
38062 * Removes and destroys all items in the menu
38064 removeAll : function(){
38066 while(f = this.items.first()){
38072 // MenuNav is a private utility class used internally by the Menu
38073 Roo.menu.MenuNav = function(menu){
38074 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
38075 this.scope = this.menu = menu;
38078 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
38079 doRelay : function(e, h){
38080 var k = e.getKey();
38081 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
38082 this.menu.tryActivate(0, 1);
38085 return h.call(this.scope || this, e, this.menu);
38088 up : function(e, m){
38089 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
38090 m.tryActivate(m.items.length-1, -1);
38094 down : function(e, m){
38095 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
38096 m.tryActivate(0, 1);
38100 right : function(e, m){
38102 m.activeItem.expandMenu(true);
38106 left : function(e, m){
38108 if(m.parentMenu && m.parentMenu.activeItem){
38109 m.parentMenu.activeItem.activate();
38113 enter : function(e, m){
38115 e.stopPropagation();
38116 m.activeItem.onClick(e);
38117 m.fireEvent("click", this, m.activeItem);
38123 * Ext JS Library 1.1.1
38124 * Copyright(c) 2006-2007, Ext JS, LLC.
38126 * Originally Released Under LGPL - original licence link has changed is not relivant.
38129 * <script type="text/javascript">
38133 * @class Roo.menu.MenuMgr
38134 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
38137 Roo.menu.MenuMgr = function(){
38138 var menus, active, groups = {}, attached = false, lastShow = new Date();
38140 // private - called when first menu is created
38143 active = new Roo.util.MixedCollection();
38144 Roo.get(document).addKeyListener(27, function(){
38145 if(active.length > 0){
38152 function hideAll(){
38153 if(active && active.length > 0){
38154 var c = active.clone();
38155 c.each(function(m){
38162 function onHide(m){
38164 if(active.length < 1){
38165 Roo.get(document).un("mousedown", onMouseDown);
38171 function onShow(m){
38172 var last = active.last();
38173 lastShow = new Date();
38176 Roo.get(document).on("mousedown", onMouseDown);
38180 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38181 m.parentMenu.activeChild = m;
38182 }else if(last && last.isVisible()){
38183 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
38188 function onBeforeHide(m){
38190 m.activeChild.hide();
38192 if(m.autoHideTimer){
38193 clearTimeout(m.autoHideTimer);
38194 delete m.autoHideTimer;
38199 function onBeforeShow(m){
38200 var pm = m.parentMenu;
38201 if(!pm && !m.allowOtherMenus){
38203 }else if(pm && pm.activeChild && active != m){
38204 pm.activeChild.hide();
38209 function onMouseDown(e){
38210 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38216 function onBeforeCheck(mi, state){
38218 var g = groups[mi.group];
38219 for(var i = 0, l = g.length; i < l; i++){
38221 g[i].setChecked(false);
38230 * Hides all menus that are currently visible
38232 hideAll : function(){
38237 register : function(menu){
38241 menus[menu.id] = menu;
38242 menu.on("beforehide", onBeforeHide);
38243 menu.on("hide", onHide);
38244 menu.on("beforeshow", onBeforeShow);
38245 menu.on("show", onShow);
38246 var g = menu.group;
38247 if(g && menu.events["checkchange"]){
38251 groups[g].push(menu);
38252 menu.on("checkchange", onCheck);
38257 * Returns a {@link Roo.menu.Menu} object
38258 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38259 * be used to generate and return a new Menu instance.
38261 get : function(menu){
38262 if(typeof menu == "string"){ // menu id
38263 return menus[menu];
38264 }else if(menu.events){ // menu instance
38266 }else if(typeof menu.length == 'number'){ // array of menu items?
38267 return new Roo.menu.Menu({items:menu});
38268 }else{ // otherwise, must be a config
38269 return new Roo.menu.Menu(menu);
38274 unregister : function(menu){
38275 delete menus[menu.id];
38276 menu.un("beforehide", onBeforeHide);
38277 menu.un("hide", onHide);
38278 menu.un("beforeshow", onBeforeShow);
38279 menu.un("show", onShow);
38280 var g = menu.group;
38281 if(g && menu.events["checkchange"]){
38282 groups[g].remove(menu);
38283 menu.un("checkchange", onCheck);
38288 registerCheckable : function(menuItem){
38289 var g = menuItem.group;
38294 groups[g].push(menuItem);
38295 menuItem.on("beforecheckchange", onBeforeCheck);
38300 unregisterCheckable : function(menuItem){
38301 var g = menuItem.group;
38303 groups[g].remove(menuItem);
38304 menuItem.un("beforecheckchange", onBeforeCheck);
38310 * Ext JS Library 1.1.1
38311 * Copyright(c) 2006-2007, Ext JS, LLC.
38313 * Originally Released Under LGPL - original licence link has changed is not relivant.
38316 * <script type="text/javascript">
38321 * @class Roo.menu.BaseItem
38322 * @extends Roo.Component
38324 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38325 * management and base configuration options shared by all menu components.
38327 * Creates a new BaseItem
38328 * @param {Object} config Configuration options
38330 Roo.menu.BaseItem = function(config){
38331 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38336 * Fires when this item is clicked
38337 * @param {Roo.menu.BaseItem} this
38338 * @param {Roo.EventObject} e
38343 * Fires when this item is activated
38344 * @param {Roo.menu.BaseItem} this
38348 * @event deactivate
38349 * Fires when this item is deactivated
38350 * @param {Roo.menu.BaseItem} this
38356 this.on("click", this.handler, this.scope, true);
38360 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38362 * @cfg {Function} handler
38363 * A function that will handle the click event of this menu item (defaults to undefined)
38366 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38368 canActivate : false,
38371 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38376 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38378 activeClass : "x-menu-item-active",
38380 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38382 hideOnClick : true,
38384 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38389 ctype: "Roo.menu.BaseItem",
38392 actionMode : "container",
38395 render : function(container, parentMenu){
38396 this.parentMenu = parentMenu;
38397 Roo.menu.BaseItem.superclass.render.call(this, container);
38398 this.container.menuItemId = this.id;
38402 onRender : function(container, position){
38403 this.el = Roo.get(this.el);
38404 container.dom.appendChild(this.el.dom);
38408 onClick : function(e){
38409 if(!this.disabled && this.fireEvent("click", this, e) !== false
38410 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38411 this.handleClick(e);
38418 activate : function(){
38422 var li = this.container;
38423 li.addClass(this.activeClass);
38424 this.region = li.getRegion().adjust(2, 2, -2, -2);
38425 this.fireEvent("activate", this);
38430 deactivate : function(){
38431 this.container.removeClass(this.activeClass);
38432 this.fireEvent("deactivate", this);
38436 shouldDeactivate : function(e){
38437 return !this.region || !this.region.contains(e.getPoint());
38441 handleClick : function(e){
38442 if(this.hideOnClick){
38443 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38448 expandMenu : function(autoActivate){
38453 hideMenu : function(){
38458 * Ext JS Library 1.1.1
38459 * Copyright(c) 2006-2007, Ext JS, LLC.
38461 * Originally Released Under LGPL - original licence link has changed is not relivant.
38464 * <script type="text/javascript">
38468 * @class Roo.menu.Adapter
38469 * @extends Roo.menu.BaseItem
38471 * 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.
38472 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38474 * Creates a new Adapter
38475 * @param {Object} config Configuration options
38477 Roo.menu.Adapter = function(component, config){
38478 Roo.menu.Adapter.superclass.constructor.call(this, config);
38479 this.component = component;
38481 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38483 canActivate : true,
38486 onRender : function(container, position){
38487 this.component.render(container);
38488 this.el = this.component.getEl();
38492 activate : function(){
38496 this.component.focus();
38497 this.fireEvent("activate", this);
38502 deactivate : function(){
38503 this.fireEvent("deactivate", this);
38507 disable : function(){
38508 this.component.disable();
38509 Roo.menu.Adapter.superclass.disable.call(this);
38513 enable : function(){
38514 this.component.enable();
38515 Roo.menu.Adapter.superclass.enable.call(this);
38519 * Ext JS Library 1.1.1
38520 * Copyright(c) 2006-2007, Ext JS, LLC.
38522 * Originally Released Under LGPL - original licence link has changed is not relivant.
38525 * <script type="text/javascript">
38529 * @class Roo.menu.TextItem
38530 * @extends Roo.menu.BaseItem
38531 * Adds a static text string to a menu, usually used as either a heading or group separator.
38532 * Note: old style constructor with text is still supported.
38535 * Creates a new TextItem
38536 * @param {Object} cfg Configuration
38538 Roo.menu.TextItem = function(cfg){
38539 if (typeof(cfg) == 'string') {
38542 Roo.apply(this,cfg);
38545 Roo.menu.TextItem.superclass.constructor.call(this);
38548 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38550 * @cfg {String} text Text to show on item.
38555 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38557 hideOnClick : false,
38559 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38561 itemCls : "x-menu-text",
38564 onRender : function(){
38565 var s = document.createElement("span");
38566 s.className = this.itemCls;
38567 s.innerHTML = this.text;
38569 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38573 * Ext JS Library 1.1.1
38574 * Copyright(c) 2006-2007, Ext JS, LLC.
38576 * Originally Released Under LGPL - original licence link has changed is not relivant.
38579 * <script type="text/javascript">
38583 * @class Roo.menu.Separator
38584 * @extends Roo.menu.BaseItem
38585 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38586 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38588 * @param {Object} config Configuration options
38590 Roo.menu.Separator = function(config){
38591 Roo.menu.Separator.superclass.constructor.call(this, config);
38594 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38596 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38598 itemCls : "x-menu-sep",
38600 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38602 hideOnClick : false,
38605 onRender : function(li){
38606 var s = document.createElement("span");
38607 s.className = this.itemCls;
38608 s.innerHTML = " ";
38610 li.addClass("x-menu-sep-li");
38611 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38615 * Ext JS Library 1.1.1
38616 * Copyright(c) 2006-2007, Ext JS, LLC.
38618 * Originally Released Under LGPL - original licence link has changed is not relivant.
38621 * <script type="text/javascript">
38624 * @class Roo.menu.Item
38625 * @extends Roo.menu.BaseItem
38626 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38627 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38628 * activation and click handling.
38630 * Creates a new Item
38631 * @param {Object} config Configuration options
38633 Roo.menu.Item = function(config){
38634 Roo.menu.Item.superclass.constructor.call(this, config);
38636 this.menu = Roo.menu.MenuMgr.get(this.menu);
38639 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38641 * @cfg {Roo.menu.Menu} menu
38645 * @cfg {String} text
38646 * The text to show on the menu item.
38650 * @cfg {String} HTML to render in menu
38651 * The text to show on the menu item (HTML version).
38655 * @cfg {String} icon
38656 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38660 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38662 itemCls : "x-menu-item",
38664 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38666 canActivate : true,
38668 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38671 // doc'd in BaseItem
38675 ctype: "Roo.menu.Item",
38678 onRender : function(container, position){
38679 var el = document.createElement("a");
38680 el.hideFocus = true;
38681 el.unselectable = "on";
38682 el.href = this.href || "#";
38683 if(this.hrefTarget){
38684 el.target = this.hrefTarget;
38686 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38688 var html = this.html.length ? this.html : String.format('{0}',this.text);
38690 el.innerHTML = String.format(
38691 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38692 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38694 Roo.menu.Item.superclass.onRender.call(this, container, position);
38698 * Sets the text to display in this menu item
38699 * @param {String} text The text to display
38700 * @param {Boolean} isHTML true to indicate text is pure html.
38702 setText : function(text, isHTML){
38710 var html = this.html.length ? this.html : String.format('{0}',this.text);
38712 this.el.update(String.format(
38713 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38714 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38715 this.parentMenu.autoWidth();
38720 handleClick : function(e){
38721 if(!this.href){ // if no link defined, stop the event automatically
38724 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38728 activate : function(autoExpand){
38729 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38739 shouldDeactivate : function(e){
38740 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38741 if(this.menu && this.menu.isVisible()){
38742 return !this.menu.getEl().getRegion().contains(e.getPoint());
38750 deactivate : function(){
38751 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38756 expandMenu : function(autoActivate){
38757 if(!this.disabled && this.menu){
38758 clearTimeout(this.hideTimer);
38759 delete this.hideTimer;
38760 if(!this.menu.isVisible() && !this.showTimer){
38761 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38762 }else if (this.menu.isVisible() && autoActivate){
38763 this.menu.tryActivate(0, 1);
38769 deferExpand : function(autoActivate){
38770 delete this.showTimer;
38771 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38773 this.menu.tryActivate(0, 1);
38778 hideMenu : function(){
38779 clearTimeout(this.showTimer);
38780 delete this.showTimer;
38781 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38782 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38787 deferHide : function(){
38788 delete this.hideTimer;
38793 * Ext JS Library 1.1.1
38794 * Copyright(c) 2006-2007, Ext JS, LLC.
38796 * Originally Released Under LGPL - original licence link has changed is not relivant.
38799 * <script type="text/javascript">
38803 * @class Roo.menu.CheckItem
38804 * @extends Roo.menu.Item
38805 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38807 * Creates a new CheckItem
38808 * @param {Object} config Configuration options
38810 Roo.menu.CheckItem = function(config){
38811 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38814 * @event beforecheckchange
38815 * Fires before the checked value is set, providing an opportunity to cancel if needed
38816 * @param {Roo.menu.CheckItem} this
38817 * @param {Boolean} checked The new checked value that will be set
38819 "beforecheckchange" : true,
38821 * @event checkchange
38822 * Fires after the checked value has been set
38823 * @param {Roo.menu.CheckItem} this
38824 * @param {Boolean} checked The checked value that was set
38826 "checkchange" : true
38828 if(this.checkHandler){
38829 this.on('checkchange', this.checkHandler, this.scope);
38832 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38834 * @cfg {String} group
38835 * All check items with the same group name will automatically be grouped into a single-select
38836 * radio button group (defaults to '')
38839 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38841 itemCls : "x-menu-item x-menu-check-item",
38843 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38845 groupClass : "x-menu-group-item",
38848 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38849 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38850 * initialized with checked = true will be rendered as checked.
38855 ctype: "Roo.menu.CheckItem",
38858 onRender : function(c){
38859 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38861 this.el.addClass(this.groupClass);
38863 Roo.menu.MenuMgr.registerCheckable(this);
38865 this.checked = false;
38866 this.setChecked(true, true);
38871 destroy : function(){
38873 Roo.menu.MenuMgr.unregisterCheckable(this);
38875 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38879 * Set the checked state of this item
38880 * @param {Boolean} checked The new checked value
38881 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38883 setChecked : function(state, suppressEvent){
38884 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38885 if(this.container){
38886 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38888 this.checked = state;
38889 if(suppressEvent !== true){
38890 this.fireEvent("checkchange", this, state);
38896 handleClick : function(e){
38897 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38898 this.setChecked(!this.checked);
38900 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38904 * Ext JS Library 1.1.1
38905 * Copyright(c) 2006-2007, Ext JS, LLC.
38907 * Originally Released Under LGPL - original licence link has changed is not relivant.
38910 * <script type="text/javascript">
38914 * @class Roo.menu.DateItem
38915 * @extends Roo.menu.Adapter
38916 * A menu item that wraps the {@link Roo.DatPicker} component.
38918 * Creates a new DateItem
38919 * @param {Object} config Configuration options
38921 Roo.menu.DateItem = function(config){
38922 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38923 /** The Roo.DatePicker object @type Roo.DatePicker */
38924 this.picker = this.component;
38925 this.addEvents({select: true});
38927 this.picker.on("render", function(picker){
38928 picker.getEl().swallowEvent("click");
38929 picker.container.addClass("x-menu-date-item");
38932 this.picker.on("select", this.onSelect, this);
38935 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38937 onSelect : function(picker, date){
38938 this.fireEvent("select", this, date, picker);
38939 Roo.menu.DateItem.superclass.handleClick.call(this);
38943 * Ext JS Library 1.1.1
38944 * Copyright(c) 2006-2007, Ext JS, LLC.
38946 * Originally Released Under LGPL - original licence link has changed is not relivant.
38949 * <script type="text/javascript">
38953 * @class Roo.menu.ColorItem
38954 * @extends Roo.menu.Adapter
38955 * A menu item that wraps the {@link Roo.ColorPalette} component.
38957 * Creates a new ColorItem
38958 * @param {Object} config Configuration options
38960 Roo.menu.ColorItem = function(config){
38961 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38962 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38963 this.palette = this.component;
38964 this.relayEvents(this.palette, ["select"]);
38965 if(this.selectHandler){
38966 this.on('select', this.selectHandler, this.scope);
38969 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38971 * Ext JS Library 1.1.1
38972 * Copyright(c) 2006-2007, Ext JS, LLC.
38974 * Originally Released Under LGPL - original licence link has changed is not relivant.
38977 * <script type="text/javascript">
38982 * @class Roo.menu.DateMenu
38983 * @extends Roo.menu.Menu
38984 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38986 * Creates a new DateMenu
38987 * @param {Object} config Configuration options
38989 Roo.menu.DateMenu = function(config){
38990 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38992 var di = new Roo.menu.DateItem(config);
38995 * The {@link Roo.DatePicker} instance for this DateMenu
38998 this.picker = di.picker;
39001 * @param {DatePicker} picker
39002 * @param {Date} date
39004 this.relayEvents(di, ["select"]);
39005 this.on('beforeshow', function(){
39007 this.picker.hideMonthPicker(false);
39011 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
39015 * Ext JS Library 1.1.1
39016 * Copyright(c) 2006-2007, Ext JS, LLC.
39018 * Originally Released Under LGPL - original licence link has changed is not relivant.
39021 * <script type="text/javascript">
39026 * @class Roo.menu.ColorMenu
39027 * @extends Roo.menu.Menu
39028 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
39030 * Creates a new ColorMenu
39031 * @param {Object} config Configuration options
39033 Roo.menu.ColorMenu = function(config){
39034 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
39036 var ci = new Roo.menu.ColorItem(config);
39039 * The {@link Roo.ColorPalette} instance for this ColorMenu
39040 * @type ColorPalette
39042 this.palette = ci.palette;
39045 * @param {ColorPalette} palette
39046 * @param {String} color
39048 this.relayEvents(ci, ["select"]);
39050 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
39052 * Ext JS Library 1.1.1
39053 * Copyright(c) 2006-2007, Ext JS, LLC.
39055 * Originally Released Under LGPL - original licence link has changed is not relivant.
39058 * <script type="text/javascript">
39062 * @class Roo.form.TextItem
39063 * @extends Roo.BoxComponent
39064 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39066 * Creates a new TextItem
39067 * @param {Object} config Configuration options
39069 Roo.form.TextItem = function(config){
39070 Roo.form.TextItem.superclass.constructor.call(this, config);
39073 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
39076 * @cfg {String} tag the tag for this item (default div)
39080 * @cfg {String} html the content for this item
39084 getAutoCreate : function()
39097 onRender : function(ct, position)
39099 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
39102 var cfg = this.getAutoCreate();
39104 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39106 if (!cfg.name.length) {
39109 this.el = ct.createChild(cfg, position);
39114 * @param {String} html update the Contents of the element.
39116 setHTML : function(html)
39118 this.fieldEl.dom.innerHTML = html;
39123 * Ext JS Library 1.1.1
39124 * Copyright(c) 2006-2007, Ext JS, LLC.
39126 * Originally Released Under LGPL - original licence link has changed is not relivant.
39129 * <script type="text/javascript">
39133 * @class Roo.form.Field
39134 * @extends Roo.BoxComponent
39135 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39137 * Creates a new Field
39138 * @param {Object} config Configuration options
39140 Roo.form.Field = function(config){
39141 Roo.form.Field.superclass.constructor.call(this, config);
39144 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
39146 * @cfg {String} fieldLabel Label to use when rendering a form.
39149 * @cfg {String} qtip Mouse over tip
39153 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
39155 invalidClass : "x-form-invalid",
39157 * @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")
39159 invalidText : "The value in this field is invalid",
39161 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
39163 focusClass : "x-form-focus",
39165 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
39166 automatic validation (defaults to "keyup").
39168 validationEvent : "keyup",
39170 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
39172 validateOnBlur : true,
39174 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39176 validationDelay : 250,
39178 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39179 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39181 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39183 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39185 fieldClass : "x-form-field",
39187 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
39190 ----------- ----------------------------------------------------------------------
39191 qtip Display a quick tip when the user hovers over the field
39192 title Display a default browser title attribute popup
39193 under Add a block div beneath the field containing the error text
39194 side Add an error icon to the right of the field with a popup on hover
39195 [element id] Add the error text directly to the innerHTML of the specified element
39198 msgTarget : 'qtip',
39200 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39205 * @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.
39210 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39215 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39217 inputType : undefined,
39220 * @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).
39222 tabIndex : undefined,
39225 isFormField : true,
39230 * @property {Roo.Element} fieldEl
39231 * Element Containing the rendered Field (with label etc.)
39234 * @cfg {Mixed} value A value to initialize this field with.
39239 * @cfg {String} name The field's HTML name attribute.
39242 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39245 loadedValue : false,
39249 initComponent : function(){
39250 Roo.form.Field.superclass.initComponent.call(this);
39254 * Fires when this field receives input focus.
39255 * @param {Roo.form.Field} this
39260 * Fires when this field loses input focus.
39261 * @param {Roo.form.Field} this
39265 * @event specialkey
39266 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39267 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39268 * @param {Roo.form.Field} this
39269 * @param {Roo.EventObject} e The event object
39274 * Fires just before the field blurs if the field value has changed.
39275 * @param {Roo.form.Field} this
39276 * @param {Mixed} newValue The new value
39277 * @param {Mixed} oldValue The original value
39282 * Fires after the field has been marked as invalid.
39283 * @param {Roo.form.Field} this
39284 * @param {String} msg The validation message
39289 * Fires after the field has been validated with no errors.
39290 * @param {Roo.form.Field} this
39295 * Fires after the key up
39296 * @param {Roo.form.Field} this
39297 * @param {Roo.EventObject} e The event Object
39304 * Returns the name attribute of the field if available
39305 * @return {String} name The field name
39307 getName: function(){
39308 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39312 onRender : function(ct, position){
39313 Roo.form.Field.superclass.onRender.call(this, ct, position);
39315 var cfg = this.getAutoCreate();
39317 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39319 if (!cfg.name.length) {
39322 if(this.inputType){
39323 cfg.type = this.inputType;
39325 this.el = ct.createChild(cfg, position);
39327 var type = this.el.dom.type;
39329 if(type == 'password'){
39332 this.el.addClass('x-form-'+type);
39335 this.el.dom.readOnly = true;
39337 if(this.tabIndex !== undefined){
39338 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39341 this.el.addClass([this.fieldClass, this.cls]);
39346 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39347 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39348 * @return {Roo.form.Field} this
39350 applyTo : function(target){
39351 this.allowDomMove = false;
39352 this.el = Roo.get(target);
39353 this.render(this.el.dom.parentNode);
39358 initValue : function(){
39359 if(this.value !== undefined){
39360 this.setValue(this.value);
39361 }else if(this.el.dom.value.length > 0){
39362 this.setValue(this.el.dom.value);
39367 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39368 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39370 isDirty : function() {
39371 if(this.disabled) {
39374 return String(this.getValue()) !== String(this.originalValue);
39378 * stores the current value in loadedValue
39380 resetHasChanged : function()
39382 this.loadedValue = String(this.getValue());
39385 * checks the current value against the 'loaded' value.
39386 * Note - will return false if 'resetHasChanged' has not been called first.
39388 hasChanged : function()
39390 if(this.disabled || this.readOnly) {
39393 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39399 afterRender : function(){
39400 Roo.form.Field.superclass.afterRender.call(this);
39405 fireKey : function(e){
39406 //Roo.log('field ' + e.getKey());
39407 if(e.isNavKeyPress()){
39408 this.fireEvent("specialkey", this, e);
39413 * Resets the current field value to the originally loaded value and clears any validation messages
39415 reset : function(){
39416 this.setValue(this.resetValue);
39417 this.originalValue = this.getValue();
39418 this.clearInvalid();
39422 initEvents : function(){
39423 // safari killled keypress - so keydown is now used..
39424 this.el.on("keydown" , this.fireKey, this);
39425 this.el.on("focus", this.onFocus, this);
39426 this.el.on("blur", this.onBlur, this);
39427 this.el.relayEvent('keyup', this);
39429 // reference to original value for reset
39430 this.originalValue = this.getValue();
39431 this.resetValue = this.getValue();
39435 onFocus : function(){
39436 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39437 this.el.addClass(this.focusClass);
39439 if(!this.hasFocus){
39440 this.hasFocus = true;
39441 this.startValue = this.getValue();
39442 this.fireEvent("focus", this);
39446 beforeBlur : Roo.emptyFn,
39449 onBlur : function(){
39451 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39452 this.el.removeClass(this.focusClass);
39454 this.hasFocus = false;
39455 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39458 var v = this.getValue();
39459 if(String(v) !== String(this.startValue)){
39460 this.fireEvent('change', this, v, this.startValue);
39462 this.fireEvent("blur", this);
39466 * Returns whether or not the field value is currently valid
39467 * @param {Boolean} preventMark True to disable marking the field invalid
39468 * @return {Boolean} True if the value is valid, else false
39470 isValid : function(preventMark){
39474 var restore = this.preventMark;
39475 this.preventMark = preventMark === true;
39476 var v = this.validateValue(this.processValue(this.getRawValue()));
39477 this.preventMark = restore;
39482 * Validates the field value
39483 * @return {Boolean} True if the value is valid, else false
39485 validate : function(){
39486 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39487 this.clearInvalid();
39493 processValue : function(value){
39498 // Subclasses should provide the validation implementation by overriding this
39499 validateValue : function(value){
39504 * Mark this field as invalid
39505 * @param {String} msg The validation message
39507 markInvalid : function(msg){
39508 if(!this.rendered || this.preventMark){ // not rendered
39512 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39514 obj.el.addClass(this.invalidClass);
39515 msg = msg || this.invalidText;
39516 switch(this.msgTarget){
39518 obj.el.dom.qtip = msg;
39519 obj.el.dom.qclass = 'x-form-invalid-tip';
39520 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39521 Roo.QuickTips.enable();
39525 this.el.dom.title = msg;
39529 var elp = this.el.findParent('.x-form-element', 5, true);
39530 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39531 this.errorEl.setWidth(elp.getWidth(true)-20);
39533 this.errorEl.update(msg);
39534 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39537 if(!this.errorIcon){
39538 var elp = this.el.findParent('.x-form-element', 5, true);
39539 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39541 this.alignErrorIcon();
39542 this.errorIcon.dom.qtip = msg;
39543 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39544 this.errorIcon.show();
39545 this.on('resize', this.alignErrorIcon, this);
39548 var t = Roo.getDom(this.msgTarget);
39550 t.style.display = this.msgDisplay;
39553 this.fireEvent('invalid', this, msg);
39557 alignErrorIcon : function(){
39558 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39562 * Clear any invalid styles/messages for this field
39564 clearInvalid : function(){
39565 if(!this.rendered || this.preventMark){ // not rendered
39568 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39570 obj.el.removeClass(this.invalidClass);
39571 switch(this.msgTarget){
39573 obj.el.dom.qtip = '';
39576 this.el.dom.title = '';
39580 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39584 if(this.errorIcon){
39585 this.errorIcon.dom.qtip = '';
39586 this.errorIcon.hide();
39587 this.un('resize', this.alignErrorIcon, this);
39591 var t = Roo.getDom(this.msgTarget);
39593 t.style.display = 'none';
39596 this.fireEvent('valid', this);
39600 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39601 * @return {Mixed} value The field value
39603 getRawValue : function(){
39604 var v = this.el.getValue();
39610 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39611 * @return {Mixed} value The field value
39613 getValue : function(){
39614 var v = this.el.getValue();
39620 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39621 * @param {Mixed} value The value to set
39623 setRawValue : function(v){
39624 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39628 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39629 * @param {Mixed} value The value to set
39631 setValue : function(v){
39634 this.el.dom.value = (v === null || v === undefined ? '' : v);
39639 adjustSize : function(w, h){
39640 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39641 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39645 adjustWidth : function(tag, w){
39646 tag = tag.toLowerCase();
39647 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39648 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39649 if(tag == 'input'){
39652 if(tag == 'textarea'){
39655 }else if(Roo.isOpera){
39656 if(tag == 'input'){
39659 if(tag == 'textarea'){
39669 // anything other than normal should be considered experimental
39670 Roo.form.Field.msgFx = {
39672 show: function(msgEl, f){
39673 msgEl.setDisplayed('block');
39676 hide : function(msgEl, f){
39677 msgEl.setDisplayed(false).update('');
39682 show: function(msgEl, f){
39683 msgEl.slideIn('t', {stopFx:true});
39686 hide : function(msgEl, f){
39687 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39692 show: function(msgEl, f){
39693 msgEl.fixDisplay();
39694 msgEl.alignTo(f.el, 'tl-tr');
39695 msgEl.slideIn('l', {stopFx:true});
39698 hide : function(msgEl, f){
39699 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39704 * Ext JS Library 1.1.1
39705 * Copyright(c) 2006-2007, Ext JS, LLC.
39707 * Originally Released Under LGPL - original licence link has changed is not relivant.
39710 * <script type="text/javascript">
39715 * @class Roo.form.TextField
39716 * @extends Roo.form.Field
39717 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39718 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39720 * Creates a new TextField
39721 * @param {Object} config Configuration options
39723 Roo.form.TextField = function(config){
39724 Roo.form.TextField.superclass.constructor.call(this, config);
39728 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39729 * according to the default logic, but this event provides a hook for the developer to apply additional
39730 * logic at runtime to resize the field if needed.
39731 * @param {Roo.form.Field} this This text field
39732 * @param {Number} width The new field width
39738 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39740 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39744 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39748 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39752 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39756 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39760 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39762 disableKeyFilter : false,
39764 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39768 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39772 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39774 maxLength : Number.MAX_VALUE,
39776 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39778 minLengthText : "The minimum length for this field is {0}",
39780 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39782 maxLengthText : "The maximum length for this field is {0}",
39784 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39786 selectOnFocus : false,
39788 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39790 allowLeadingSpace : false,
39792 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39794 blankText : "This field is required",
39796 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39797 * If available, this function will be called only after the basic validators all return true, and will be passed the
39798 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39802 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39803 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39804 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39808 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39812 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39818 initEvents : function()
39820 if (this.emptyText) {
39821 this.el.attr('placeholder', this.emptyText);
39824 Roo.form.TextField.superclass.initEvents.call(this);
39825 if(this.validationEvent == 'keyup'){
39826 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39827 this.el.on('keyup', this.filterValidation, this);
39829 else if(this.validationEvent !== false){
39830 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39833 if(this.selectOnFocus){
39834 this.on("focus", this.preFocus, this);
39836 if (!this.allowLeadingSpace) {
39837 this.on('blur', this.cleanLeadingSpace, this);
39840 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39841 this.el.on("keypress", this.filterKeys, this);
39844 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39845 this.el.on("click", this.autoSize, this);
39847 if(this.el.is('input[type=password]') && Roo.isSafari){
39848 this.el.on('keydown', this.SafariOnKeyDown, this);
39852 processValue : function(value){
39853 if(this.stripCharsRe){
39854 var newValue = value.replace(this.stripCharsRe, '');
39855 if(newValue !== value){
39856 this.setRawValue(newValue);
39863 filterValidation : function(e){
39864 if(!e.isNavKeyPress()){
39865 this.validationTask.delay(this.validationDelay);
39870 onKeyUp : function(e){
39871 if(!e.isNavKeyPress()){
39875 // private - clean the leading white space
39876 cleanLeadingSpace : function(e)
39878 if ( this.inputType == 'file') {
39882 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39885 * Resets the current field value to the originally-loaded value and clears any validation messages.
39888 reset : function(){
39889 Roo.form.TextField.superclass.reset.call(this);
39893 preFocus : function(){
39895 if(this.selectOnFocus){
39896 this.el.dom.select();
39902 filterKeys : function(e){
39903 var k = e.getKey();
39904 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39907 var c = e.getCharCode(), cc = String.fromCharCode(c);
39908 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39911 if(!this.maskRe.test(cc)){
39916 setValue : function(v){
39918 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39924 * Validates a value according to the field's validation rules and marks the field as invalid
39925 * if the validation fails
39926 * @param {Mixed} value The value to validate
39927 * @return {Boolean} True if the value is valid, else false
39929 validateValue : function(value){
39930 if(value.length < 1) { // if it's blank
39931 if(this.allowBlank){
39932 this.clearInvalid();
39935 this.markInvalid(this.blankText);
39939 if(value.length < this.minLength){
39940 this.markInvalid(String.format(this.minLengthText, this.minLength));
39943 if(value.length > this.maxLength){
39944 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39948 var vt = Roo.form.VTypes;
39949 if(!vt[this.vtype](value, this)){
39950 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39954 if(typeof this.validator == "function"){
39955 var msg = this.validator(value);
39957 this.markInvalid(msg);
39961 if(this.regex && !this.regex.test(value)){
39962 this.markInvalid(this.regexText);
39969 * Selects text in this field
39970 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39971 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39973 selectText : function(start, end){
39974 var v = this.getRawValue();
39976 start = start === undefined ? 0 : start;
39977 end = end === undefined ? v.length : end;
39978 var d = this.el.dom;
39979 if(d.setSelectionRange){
39980 d.setSelectionRange(start, end);
39981 }else if(d.createTextRange){
39982 var range = d.createTextRange();
39983 range.moveStart("character", start);
39984 range.moveEnd("character", v.length-end);
39991 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39992 * This only takes effect if grow = true, and fires the autosize event.
39994 autoSize : function(){
39995 if(!this.grow || !this.rendered){
39999 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
40002 var v = el.dom.value;
40003 var d = document.createElement('div');
40004 d.appendChild(document.createTextNode(v));
40008 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
40009 this.el.setWidth(w);
40010 this.fireEvent("autosize", this, w);
40014 SafariOnKeyDown : function(event)
40016 // this is a workaround for a password hang bug on chrome/ webkit.
40018 var isSelectAll = false;
40020 if(this.el.dom.selectionEnd > 0){
40021 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
40023 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
40024 event.preventDefault();
40029 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
40031 event.preventDefault();
40032 // this is very hacky as keydown always get's upper case.
40034 var cc = String.fromCharCode(event.getCharCode());
40037 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
40045 * Ext JS Library 1.1.1
40046 * Copyright(c) 2006-2007, Ext JS, LLC.
40048 * Originally Released Under LGPL - original licence link has changed is not relivant.
40051 * <script type="text/javascript">
40055 * @class Roo.form.Hidden
40056 * @extends Roo.form.TextField
40057 * Simple Hidden element used on forms
40059 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
40062 * Creates a new Hidden form element.
40063 * @param {Object} config Configuration options
40068 // easy hidden field...
40069 Roo.form.Hidden = function(config){
40070 Roo.form.Hidden.superclass.constructor.call(this, config);
40073 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
40075 inputType: 'hidden',
40078 labelSeparator: '',
40080 itemCls : 'x-form-item-display-none'
40088 * Ext JS Library 1.1.1
40089 * Copyright(c) 2006-2007, Ext JS, LLC.
40091 * Originally Released Under LGPL - original licence link has changed is not relivant.
40094 * <script type="text/javascript">
40098 * @class Roo.form.TriggerField
40099 * @extends Roo.form.TextField
40100 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
40101 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
40102 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
40103 * for which you can provide a custom implementation. For example:
40105 var trigger = new Roo.form.TriggerField();
40106 trigger.onTriggerClick = myTriggerFn;
40107 trigger.applyTo('my-field');
40110 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
40111 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
40112 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40113 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
40115 * Create a new TriggerField.
40116 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
40117 * to the base TextField)
40119 Roo.form.TriggerField = function(config){
40120 this.mimicing = false;
40121 Roo.form.TriggerField.superclass.constructor.call(this, config);
40124 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
40126 * @cfg {String} triggerClass A CSS class to apply to the trigger
40129 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40130 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
40132 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
40134 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
40138 /** @cfg {Boolean} grow @hide */
40139 /** @cfg {Number} growMin @hide */
40140 /** @cfg {Number} growMax @hide */
40146 autoSize: Roo.emptyFn,
40150 deferHeight : true,
40153 actionMode : 'wrap',
40155 onResize : function(w, h){
40156 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
40157 if(typeof w == 'number'){
40158 var x = w - this.trigger.getWidth();
40159 this.el.setWidth(this.adjustWidth('input', x));
40160 this.trigger.setStyle('left', x+'px');
40165 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40168 getResizeEl : function(){
40173 getPositionEl : function(){
40178 alignErrorIcon : function(){
40179 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40183 onRender : function(ct, position){
40184 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40185 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
40186 this.trigger = this.wrap.createChild(this.triggerConfig ||
40187 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
40188 if(this.hideTrigger){
40189 this.trigger.setDisplayed(false);
40191 this.initTrigger();
40193 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
40198 initTrigger : function(){
40199 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40200 this.trigger.addClassOnOver('x-form-trigger-over');
40201 this.trigger.addClassOnClick('x-form-trigger-click');
40205 onDestroy : function(){
40207 this.trigger.removeAllListeners();
40208 this.trigger.remove();
40211 this.wrap.remove();
40213 Roo.form.TriggerField.superclass.onDestroy.call(this);
40217 onFocus : function(){
40218 Roo.form.TriggerField.superclass.onFocus.call(this);
40219 if(!this.mimicing){
40220 this.wrap.addClass('x-trigger-wrap-focus');
40221 this.mimicing = true;
40222 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40223 if(this.monitorTab){
40224 this.el.on("keydown", this.checkTab, this);
40230 checkTab : function(e){
40231 if(e.getKey() == e.TAB){
40232 this.triggerBlur();
40237 onBlur : function(){
40242 mimicBlur : function(e, t){
40243 if(!this.wrap.contains(t) && this.validateBlur()){
40244 this.triggerBlur();
40249 triggerBlur : function(){
40250 this.mimicing = false;
40251 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40252 if(this.monitorTab){
40253 this.el.un("keydown", this.checkTab, this);
40255 this.wrap.removeClass('x-trigger-wrap-focus');
40256 Roo.form.TriggerField.superclass.onBlur.call(this);
40260 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40261 validateBlur : function(e, t){
40266 onDisable : function(){
40267 Roo.form.TriggerField.superclass.onDisable.call(this);
40269 this.wrap.addClass('x-item-disabled');
40274 onEnable : function(){
40275 Roo.form.TriggerField.superclass.onEnable.call(this);
40277 this.wrap.removeClass('x-item-disabled');
40282 onShow : function(){
40283 var ae = this.getActionEl();
40286 ae.dom.style.display = '';
40287 ae.dom.style.visibility = 'visible';
40293 onHide : function(){
40294 var ae = this.getActionEl();
40295 ae.dom.style.display = 'none';
40299 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40300 * by an implementing function.
40302 * @param {EventObject} e
40304 onTriggerClick : Roo.emptyFn
40307 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40308 // to be extended by an implementing class. For an example of implementing this class, see the custom
40309 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40310 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40311 initComponent : function(){
40312 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40314 this.triggerConfig = {
40315 tag:'span', cls:'x-form-twin-triggers', cn:[
40316 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40317 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40321 getTrigger : function(index){
40322 return this.triggers[index];
40325 initTrigger : function(){
40326 var ts = this.trigger.select('.x-form-trigger', true);
40327 this.wrap.setStyle('overflow', 'hidden');
40328 var triggerField = this;
40329 ts.each(function(t, all, index){
40330 t.hide = function(){
40331 var w = triggerField.wrap.getWidth();
40332 this.dom.style.display = 'none';
40333 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40335 t.show = function(){
40336 var w = triggerField.wrap.getWidth();
40337 this.dom.style.display = '';
40338 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40340 var triggerIndex = 'Trigger'+(index+1);
40342 if(this['hide'+triggerIndex]){
40343 t.dom.style.display = 'none';
40345 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40346 t.addClassOnOver('x-form-trigger-over');
40347 t.addClassOnClick('x-form-trigger-click');
40349 this.triggers = ts.elements;
40352 onTrigger1Click : Roo.emptyFn,
40353 onTrigger2Click : Roo.emptyFn
40356 * Ext JS Library 1.1.1
40357 * Copyright(c) 2006-2007, Ext JS, LLC.
40359 * Originally Released Under LGPL - original licence link has changed is not relivant.
40362 * <script type="text/javascript">
40366 * @class Roo.form.TextArea
40367 * @extends Roo.form.TextField
40368 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40369 * support for auto-sizing.
40371 * Creates a new TextArea
40372 * @param {Object} config Configuration options
40374 Roo.form.TextArea = function(config){
40375 Roo.form.TextArea.superclass.constructor.call(this, config);
40376 // these are provided exchanges for backwards compat
40377 // minHeight/maxHeight were replaced by growMin/growMax to be
40378 // compatible with TextField growing config values
40379 if(this.minHeight !== undefined){
40380 this.growMin = this.minHeight;
40382 if(this.maxHeight !== undefined){
40383 this.growMax = this.maxHeight;
40387 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40389 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40393 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40397 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40398 * in the field (equivalent to setting overflow: hidden, defaults to false)
40400 preventScrollbars: false,
40402 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40403 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40407 onRender : function(ct, position){
40409 this.defaultAutoCreate = {
40411 style:"width:300px;height:60px;",
40412 autocomplete: "new-password"
40415 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40417 this.textSizeEl = Roo.DomHelper.append(document.body, {
40418 tag: "pre", cls: "x-form-grow-sizer"
40420 if(this.preventScrollbars){
40421 this.el.setStyle("overflow", "hidden");
40423 this.el.setHeight(this.growMin);
40427 onDestroy : function(){
40428 if(this.textSizeEl){
40429 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40431 Roo.form.TextArea.superclass.onDestroy.call(this);
40435 onKeyUp : function(e){
40436 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40442 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40443 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40445 autoSize : function(){
40446 if(!this.grow || !this.textSizeEl){
40450 var v = el.dom.value;
40451 var ts = this.textSizeEl;
40454 ts.appendChild(document.createTextNode(v));
40457 Roo.fly(ts).setWidth(this.el.getWidth());
40459 v = "  ";
40462 v = v.replace(/\n/g, '<p> </p>');
40464 v += " \n ";
40467 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40468 if(h != this.lastHeight){
40469 this.lastHeight = h;
40470 this.el.setHeight(h);
40471 this.fireEvent("autosize", this, h);
40476 * Ext JS Library 1.1.1
40477 * Copyright(c) 2006-2007, Ext JS, LLC.
40479 * Originally Released Under LGPL - original licence link has changed is not relivant.
40482 * <script type="text/javascript">
40487 * @class Roo.form.NumberField
40488 * @extends Roo.form.TextField
40489 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40491 * Creates a new NumberField
40492 * @param {Object} config Configuration options
40494 Roo.form.NumberField = function(config){
40495 Roo.form.NumberField.superclass.constructor.call(this, config);
40498 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40500 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40502 fieldClass: "x-form-field x-form-num-field",
40504 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40506 allowDecimals : true,
40508 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40510 decimalSeparator : ".",
40512 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40514 decimalPrecision : 2,
40516 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40518 allowNegative : true,
40520 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40522 minValue : Number.NEGATIVE_INFINITY,
40524 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40526 maxValue : Number.MAX_VALUE,
40528 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40530 minText : "The minimum value for this field is {0}",
40532 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40534 maxText : "The maximum value for this field is {0}",
40536 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40537 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40539 nanText : "{0} is not a valid number",
40542 initEvents : function(){
40543 Roo.form.NumberField.superclass.initEvents.call(this);
40544 var allowed = "0123456789";
40545 if(this.allowDecimals){
40546 allowed += this.decimalSeparator;
40548 if(this.allowNegative){
40551 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40552 var keyPress = function(e){
40553 var k = e.getKey();
40554 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40557 var c = e.getCharCode();
40558 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40562 this.el.on("keypress", keyPress, this);
40566 validateValue : function(value){
40567 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40570 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40573 var num = this.parseValue(value);
40575 this.markInvalid(String.format(this.nanText, value));
40578 if(num < this.minValue){
40579 this.markInvalid(String.format(this.minText, this.minValue));
40582 if(num > this.maxValue){
40583 this.markInvalid(String.format(this.maxText, this.maxValue));
40589 getValue : function(){
40590 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40594 parseValue : function(value){
40595 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40596 return isNaN(value) ? '' : value;
40600 fixPrecision : function(value){
40601 var nan = isNaN(value);
40602 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40603 return nan ? '' : value;
40605 return parseFloat(value).toFixed(this.decimalPrecision);
40608 setValue : function(v){
40609 v = this.fixPrecision(v);
40610 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40614 decimalPrecisionFcn : function(v){
40615 return Math.floor(v);
40618 beforeBlur : function(){
40619 var v = this.parseValue(this.getRawValue());
40626 * Ext JS Library 1.1.1
40627 * Copyright(c) 2006-2007, Ext JS, LLC.
40629 * Originally Released Under LGPL - original licence link has changed is not relivant.
40632 * <script type="text/javascript">
40636 * @class Roo.form.DateField
40637 * @extends Roo.form.TriggerField
40638 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40640 * Create a new DateField
40641 * @param {Object} config
40643 Roo.form.DateField = function(config)
40645 Roo.form.DateField.superclass.constructor.call(this, config);
40651 * Fires when a date is selected
40652 * @param {Roo.form.DateField} combo This combo box
40653 * @param {Date} date The date selected
40660 if(typeof this.minValue == "string") {
40661 this.minValue = this.parseDate(this.minValue);
40663 if(typeof this.maxValue == "string") {
40664 this.maxValue = this.parseDate(this.maxValue);
40666 this.ddMatch = null;
40667 if(this.disabledDates){
40668 var dd = this.disabledDates;
40670 for(var i = 0; i < dd.length; i++){
40672 if(i != dd.length-1) {
40676 this.ddMatch = new RegExp(re + ")");
40680 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40682 * @cfg {String} format
40683 * The default date format string which can be overriden for localization support. The format must be
40684 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40688 * @cfg {String} altFormats
40689 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40690 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40692 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40694 * @cfg {Array} disabledDays
40695 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40697 disabledDays : null,
40699 * @cfg {String} disabledDaysText
40700 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40702 disabledDaysText : "Disabled",
40704 * @cfg {Array} disabledDates
40705 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40706 * expression so they are very powerful. Some examples:
40708 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40709 * <li>["03/08", "09/16"] would disable those days for every year</li>
40710 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40711 * <li>["03/../2006"] would disable every day in March 2006</li>
40712 * <li>["^03"] would disable every day in every March</li>
40714 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40715 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40717 disabledDates : null,
40719 * @cfg {String} disabledDatesText
40720 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40722 disabledDatesText : "Disabled",
40724 * @cfg {Date/String} minValue
40725 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40726 * valid format (defaults to null).
40730 * @cfg {Date/String} maxValue
40731 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40732 * valid format (defaults to null).
40736 * @cfg {String} minText
40737 * The error text to display when the date in the cell is before minValue (defaults to
40738 * 'The date in this field must be after {minValue}').
40740 minText : "The date in this field must be equal to or after {0}",
40742 * @cfg {String} maxText
40743 * The error text to display when the date in the cell is after maxValue (defaults to
40744 * 'The date in this field must be before {maxValue}').
40746 maxText : "The date in this field must be equal to or before {0}",
40748 * @cfg {String} invalidText
40749 * The error text to display when the date in the field is invalid (defaults to
40750 * '{value} is not a valid date - it must be in the format {format}').
40752 invalidText : "{0} is not a valid date - it must be in the format {1}",
40754 * @cfg {String} triggerClass
40755 * An additional CSS class used to style the trigger button. The trigger will always get the
40756 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40757 * which displays a calendar icon).
40759 triggerClass : 'x-form-date-trigger',
40763 * @cfg {Boolean} useIso
40764 * if enabled, then the date field will use a hidden field to store the
40765 * real value as iso formated date. default (false)
40769 * @cfg {String/Object} autoCreate
40770 * A DomHelper element spec, or true for a default element spec (defaults to
40771 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40774 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40777 hiddenField: false,
40779 onRender : function(ct, position)
40781 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40783 //this.el.dom.removeAttribute('name');
40784 Roo.log("Changing name?");
40785 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40786 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40788 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40789 // prevent input submission
40790 this.hiddenName = this.name;
40797 validateValue : function(value)
40799 value = this.formatDate(value);
40800 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40801 Roo.log('super failed');
40804 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40807 var svalue = value;
40808 value = this.parseDate(value);
40810 Roo.log('parse date failed' + svalue);
40811 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40814 var time = value.getTime();
40815 if(this.minValue && time < this.minValue.getTime()){
40816 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40819 if(this.maxValue && time > this.maxValue.getTime()){
40820 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40823 if(this.disabledDays){
40824 var day = value.getDay();
40825 for(var i = 0; i < this.disabledDays.length; i++) {
40826 if(day === this.disabledDays[i]){
40827 this.markInvalid(this.disabledDaysText);
40832 var fvalue = this.formatDate(value);
40833 if(this.ddMatch && this.ddMatch.test(fvalue)){
40834 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40841 // Provides logic to override the default TriggerField.validateBlur which just returns true
40842 validateBlur : function(){
40843 return !this.menu || !this.menu.isVisible();
40846 getName: function()
40848 // returns hidden if it's set..
40849 if (!this.rendered) {return ''};
40850 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40855 * Returns the current date value of the date field.
40856 * @return {Date} The date value
40858 getValue : function(){
40860 return this.hiddenField ?
40861 this.hiddenField.value :
40862 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40866 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40867 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40868 * (the default format used is "m/d/y").
40871 //All of these calls set the same date value (May 4, 2006)
40873 //Pass a date object:
40874 var dt = new Date('5/4/06');
40875 dateField.setValue(dt);
40877 //Pass a date string (default format):
40878 dateField.setValue('5/4/06');
40880 //Pass a date string (custom format):
40881 dateField.format = 'Y-m-d';
40882 dateField.setValue('2006-5-4');
40884 * @param {String/Date} date The date or valid date string
40886 setValue : function(date){
40887 if (this.hiddenField) {
40888 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40890 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40891 // make sure the value field is always stored as a date..
40892 this.value = this.parseDate(date);
40898 parseDate : function(value){
40899 if(!value || value instanceof Date){
40902 var v = Date.parseDate(value, this.format);
40903 if (!v && this.useIso) {
40904 v = Date.parseDate(value, 'Y-m-d');
40906 if(!v && this.altFormats){
40907 if(!this.altFormatsArray){
40908 this.altFormatsArray = this.altFormats.split("|");
40910 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40911 v = Date.parseDate(value, this.altFormatsArray[i]);
40918 formatDate : function(date, fmt){
40919 return (!date || !(date instanceof Date)) ?
40920 date : date.dateFormat(fmt || this.format);
40925 select: function(m, d){
40928 this.fireEvent('select', this, d);
40930 show : function(){ // retain focus styling
40934 this.focus.defer(10, this);
40935 var ml = this.menuListeners;
40936 this.menu.un("select", ml.select, this);
40937 this.menu.un("show", ml.show, this);
40938 this.menu.un("hide", ml.hide, this);
40943 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40944 onTriggerClick : function(){
40948 if(this.menu == null){
40949 this.menu = new Roo.menu.DateMenu();
40951 Roo.apply(this.menu.picker, {
40952 showClear: this.allowBlank,
40953 minDate : this.minValue,
40954 maxDate : this.maxValue,
40955 disabledDatesRE : this.ddMatch,
40956 disabledDatesText : this.disabledDatesText,
40957 disabledDays : this.disabledDays,
40958 disabledDaysText : this.disabledDaysText,
40959 format : this.useIso ? 'Y-m-d' : this.format,
40960 minText : String.format(this.minText, this.formatDate(this.minValue)),
40961 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40963 this.menu.on(Roo.apply({}, this.menuListeners, {
40966 this.menu.picker.setValue(this.getValue() || new Date());
40967 this.menu.show(this.el, "tl-bl?");
40970 beforeBlur : function(){
40971 var v = this.parseDate(this.getRawValue());
40981 isDirty : function() {
40982 if(this.disabled) {
40986 if(typeof(this.startValue) === 'undefined'){
40990 return String(this.getValue()) !== String(this.startValue);
40994 cleanLeadingSpace : function(e)
41001 * Ext JS Library 1.1.1
41002 * Copyright(c) 2006-2007, Ext JS, LLC.
41004 * Originally Released Under LGPL - original licence link has changed is not relivant.
41007 * <script type="text/javascript">
41011 * @class Roo.form.MonthField
41012 * @extends Roo.form.TriggerField
41013 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
41015 * Create a new MonthField
41016 * @param {Object} config
41018 Roo.form.MonthField = function(config){
41020 Roo.form.MonthField.superclass.constructor.call(this, config);
41026 * Fires when a date is selected
41027 * @param {Roo.form.MonthFieeld} combo This combo box
41028 * @param {Date} date The date selected
41035 if(typeof this.minValue == "string") {
41036 this.minValue = this.parseDate(this.minValue);
41038 if(typeof this.maxValue == "string") {
41039 this.maxValue = this.parseDate(this.maxValue);
41041 this.ddMatch = null;
41042 if(this.disabledDates){
41043 var dd = this.disabledDates;
41045 for(var i = 0; i < dd.length; i++){
41047 if(i != dd.length-1) {
41051 this.ddMatch = new RegExp(re + ")");
41055 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
41057 * @cfg {String} format
41058 * The default date format string which can be overriden for localization support. The format must be
41059 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41063 * @cfg {String} altFormats
41064 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
41065 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
41067 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
41069 * @cfg {Array} disabledDays
41070 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41072 disabledDays : [0,1,2,3,4,5,6],
41074 * @cfg {String} disabledDaysText
41075 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41077 disabledDaysText : "Disabled",
41079 * @cfg {Array} disabledDates
41080 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41081 * expression so they are very powerful. Some examples:
41083 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41084 * <li>["03/08", "09/16"] would disable those days for every year</li>
41085 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41086 * <li>["03/../2006"] would disable every day in March 2006</li>
41087 * <li>["^03"] would disable every day in every March</li>
41089 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41090 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41092 disabledDates : null,
41094 * @cfg {String} disabledDatesText
41095 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41097 disabledDatesText : "Disabled",
41099 * @cfg {Date/String} minValue
41100 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41101 * valid format (defaults to null).
41105 * @cfg {Date/String} maxValue
41106 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41107 * valid format (defaults to null).
41111 * @cfg {String} minText
41112 * The error text to display when the date in the cell is before minValue (defaults to
41113 * 'The date in this field must be after {minValue}').
41115 minText : "The date in this field must be equal to or after {0}",
41117 * @cfg {String} maxTextf
41118 * The error text to display when the date in the cell is after maxValue (defaults to
41119 * 'The date in this field must be before {maxValue}').
41121 maxText : "The date in this field must be equal to or before {0}",
41123 * @cfg {String} invalidText
41124 * The error text to display when the date in the field is invalid (defaults to
41125 * '{value} is not a valid date - it must be in the format {format}').
41127 invalidText : "{0} is not a valid date - it must be in the format {1}",
41129 * @cfg {String} triggerClass
41130 * An additional CSS class used to style the trigger button. The trigger will always get the
41131 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41132 * which displays a calendar icon).
41134 triggerClass : 'x-form-date-trigger',
41138 * @cfg {Boolean} useIso
41139 * if enabled, then the date field will use a hidden field to store the
41140 * real value as iso formated date. default (true)
41144 * @cfg {String/Object} autoCreate
41145 * A DomHelper element spec, or true for a default element spec (defaults to
41146 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41149 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
41152 hiddenField: false,
41154 hideMonthPicker : false,
41156 onRender : function(ct, position)
41158 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
41160 this.el.dom.removeAttribute('name');
41161 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41163 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41164 // prevent input submission
41165 this.hiddenName = this.name;
41172 validateValue : function(value)
41174 value = this.formatDate(value);
41175 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41178 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41181 var svalue = value;
41182 value = this.parseDate(value);
41184 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41187 var time = value.getTime();
41188 if(this.minValue && time < this.minValue.getTime()){
41189 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41192 if(this.maxValue && time > this.maxValue.getTime()){
41193 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41196 /*if(this.disabledDays){
41197 var day = value.getDay();
41198 for(var i = 0; i < this.disabledDays.length; i++) {
41199 if(day === this.disabledDays[i]){
41200 this.markInvalid(this.disabledDaysText);
41206 var fvalue = this.formatDate(value);
41207 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41208 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41216 // Provides logic to override the default TriggerField.validateBlur which just returns true
41217 validateBlur : function(){
41218 return !this.menu || !this.menu.isVisible();
41222 * Returns the current date value of the date field.
41223 * @return {Date} The date value
41225 getValue : function(){
41229 return this.hiddenField ?
41230 this.hiddenField.value :
41231 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41235 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41236 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41237 * (the default format used is "m/d/y").
41240 //All of these calls set the same date value (May 4, 2006)
41242 //Pass a date object:
41243 var dt = new Date('5/4/06');
41244 monthField.setValue(dt);
41246 //Pass a date string (default format):
41247 monthField.setValue('5/4/06');
41249 //Pass a date string (custom format):
41250 monthField.format = 'Y-m-d';
41251 monthField.setValue('2006-5-4');
41253 * @param {String/Date} date The date or valid date string
41255 setValue : function(date){
41256 Roo.log('month setValue' + date);
41257 // can only be first of month..
41259 var val = this.parseDate(date);
41261 if (this.hiddenField) {
41262 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41264 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41265 this.value = this.parseDate(date);
41269 parseDate : function(value){
41270 if(!value || value instanceof Date){
41271 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41274 var v = Date.parseDate(value, this.format);
41275 if (!v && this.useIso) {
41276 v = Date.parseDate(value, 'Y-m-d');
41280 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41284 if(!v && this.altFormats){
41285 if(!this.altFormatsArray){
41286 this.altFormatsArray = this.altFormats.split("|");
41288 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41289 v = Date.parseDate(value, this.altFormatsArray[i]);
41296 formatDate : function(date, fmt){
41297 return (!date || !(date instanceof Date)) ?
41298 date : date.dateFormat(fmt || this.format);
41303 select: function(m, d){
41305 this.fireEvent('select', this, d);
41307 show : function(){ // retain focus styling
41311 this.focus.defer(10, this);
41312 var ml = this.menuListeners;
41313 this.menu.un("select", ml.select, this);
41314 this.menu.un("show", ml.show, this);
41315 this.menu.un("hide", ml.hide, this);
41319 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41320 onTriggerClick : function(){
41324 if(this.menu == null){
41325 this.menu = new Roo.menu.DateMenu();
41329 Roo.apply(this.menu.picker, {
41331 showClear: this.allowBlank,
41332 minDate : this.minValue,
41333 maxDate : this.maxValue,
41334 disabledDatesRE : this.ddMatch,
41335 disabledDatesText : this.disabledDatesText,
41337 format : this.useIso ? 'Y-m-d' : this.format,
41338 minText : String.format(this.minText, this.formatDate(this.minValue)),
41339 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41342 this.menu.on(Roo.apply({}, this.menuListeners, {
41350 // hide month picker get's called when we called by 'before hide';
41352 var ignorehide = true;
41353 p.hideMonthPicker = function(disableAnim){
41357 if(this.monthPicker){
41358 Roo.log("hideMonthPicker called");
41359 if(disableAnim === true){
41360 this.monthPicker.hide();
41362 this.monthPicker.slideOut('t', {duration:.2});
41363 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41364 p.fireEvent("select", this, this.value);
41370 Roo.log('picker set value');
41371 Roo.log(this.getValue());
41372 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41373 m.show(this.el, 'tl-bl?');
41374 ignorehide = false;
41375 // this will trigger hideMonthPicker..
41378 // hidden the day picker
41379 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41385 p.showMonthPicker.defer(100, p);
41391 beforeBlur : function(){
41392 var v = this.parseDate(this.getRawValue());
41398 /** @cfg {Boolean} grow @hide */
41399 /** @cfg {Number} growMin @hide */
41400 /** @cfg {Number} growMax @hide */
41407 * Ext JS Library 1.1.1
41408 * Copyright(c) 2006-2007, Ext JS, LLC.
41410 * Originally Released Under LGPL - original licence link has changed is not relivant.
41413 * <script type="text/javascript">
41418 * @class Roo.form.ComboBox
41419 * @extends Roo.form.TriggerField
41420 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41422 * Create a new ComboBox.
41423 * @param {Object} config Configuration options
41425 Roo.form.ComboBox = function(config){
41426 Roo.form.ComboBox.superclass.constructor.call(this, config);
41430 * Fires when the dropdown list is expanded
41431 * @param {Roo.form.ComboBox} combo This combo box
41436 * Fires when the dropdown list is collapsed
41437 * @param {Roo.form.ComboBox} combo This combo box
41441 * @event beforeselect
41442 * Fires before a list item is selected. Return false to cancel the selection.
41443 * @param {Roo.form.ComboBox} combo This combo box
41444 * @param {Roo.data.Record} record The data record returned from the underlying store
41445 * @param {Number} index The index of the selected item in the dropdown list
41447 'beforeselect' : true,
41450 * Fires when a list item is selected
41451 * @param {Roo.form.ComboBox} combo This combo box
41452 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41453 * @param {Number} index The index of the selected item in the dropdown list
41457 * @event beforequery
41458 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41459 * The event object passed has these properties:
41460 * @param {Roo.form.ComboBox} combo This combo box
41461 * @param {String} query The query
41462 * @param {Boolean} forceAll true to force "all" query
41463 * @param {Boolean} cancel true to cancel the query
41464 * @param {Object} e The query event object
41466 'beforequery': true,
41469 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41470 * @param {Roo.form.ComboBox} combo This combo box
41475 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41476 * @param {Roo.form.ComboBox} combo This combo box
41477 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41483 if(this.transform){
41484 this.allowDomMove = false;
41485 var s = Roo.getDom(this.transform);
41486 if(!this.hiddenName){
41487 this.hiddenName = s.name;
41490 this.mode = 'local';
41491 var d = [], opts = s.options;
41492 for(var i = 0, len = opts.length;i < len; i++){
41494 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41496 this.value = value;
41498 d.push([value, o.text]);
41500 this.store = new Roo.data.SimpleStore({
41502 fields: ['value', 'text'],
41505 this.valueField = 'value';
41506 this.displayField = 'text';
41508 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41509 if(!this.lazyRender){
41510 this.target = true;
41511 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41512 s.parentNode.removeChild(s); // remove it
41513 this.render(this.el.parentNode);
41515 s.parentNode.removeChild(s); // remove it
41520 this.store = Roo.factory(this.store, Roo.data);
41523 this.selectedIndex = -1;
41524 if(this.mode == 'local'){
41525 if(config.queryDelay === undefined){
41526 this.queryDelay = 10;
41528 if(config.minChars === undefined){
41534 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41536 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41539 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41540 * rendering into an Roo.Editor, defaults to false)
41543 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41544 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41547 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41550 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41551 * the dropdown list (defaults to undefined, with no header element)
41555 * @cfg {String/Roo.Template} tpl The template to use to render the output
41559 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41561 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41563 listWidth: undefined,
41565 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41566 * mode = 'remote' or 'text' if mode = 'local')
41568 displayField: undefined,
41570 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41571 * mode = 'remote' or 'value' if mode = 'local').
41572 * Note: use of a valueField requires the user make a selection
41573 * in order for a value to be mapped.
41575 valueField: undefined,
41579 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41580 * field's data value (defaults to the underlying DOM element's name)
41582 hiddenName: undefined,
41584 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41588 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41590 selectedClass: 'x-combo-selected',
41592 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41593 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41594 * which displays a downward arrow icon).
41596 triggerClass : 'x-form-arrow-trigger',
41598 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41602 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41603 * anchor positions (defaults to 'tl-bl')
41605 listAlign: 'tl-bl?',
41607 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41611 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41612 * query specified by the allQuery config option (defaults to 'query')
41614 triggerAction: 'query',
41616 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41617 * (defaults to 4, does not apply if editable = false)
41621 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41622 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41626 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41627 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41631 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41632 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41636 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41637 * when editable = true (defaults to false)
41639 selectOnFocus:false,
41641 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41643 queryParam: 'query',
41645 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41646 * when mode = 'remote' (defaults to 'Loading...')
41648 loadingText: 'Loading...',
41650 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41654 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41658 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41659 * traditional select (defaults to true)
41663 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41667 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41671 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41672 * listWidth has a higher value)
41676 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41677 * allow the user to set arbitrary text into the field (defaults to false)
41679 forceSelection:false,
41681 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41682 * if typeAhead = true (defaults to 250)
41684 typeAheadDelay : 250,
41686 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41687 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41689 valueNotFoundText : undefined,
41691 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41693 blockFocus : false,
41696 * @cfg {Boolean} disableClear Disable showing of clear button.
41698 disableClear : false,
41700 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41702 alwaysQuery : false,
41708 // element that contains real text value.. (when hidden is used..)
41711 onRender : function(ct, position)
41713 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41715 if(this.hiddenName){
41716 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41718 this.hiddenField.value =
41719 this.hiddenValue !== undefined ? this.hiddenValue :
41720 this.value !== undefined ? this.value : '';
41722 // prevent input submission
41723 this.el.dom.removeAttribute('name');
41729 this.el.dom.setAttribute('autocomplete', 'off');
41732 var cls = 'x-combo-list';
41734 this.list = new Roo.Layer({
41735 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41738 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41739 this.list.setWidth(lw);
41740 this.list.swallowEvent('mousewheel');
41741 this.assetHeight = 0;
41744 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41745 this.assetHeight += this.header.getHeight();
41748 this.innerList = this.list.createChild({cls:cls+'-inner'});
41749 this.innerList.on('mouseover', this.onViewOver, this);
41750 this.innerList.on('mousemove', this.onViewMove, this);
41751 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41753 if(this.allowBlank && !this.pageSize && !this.disableClear){
41754 this.footer = this.list.createChild({cls:cls+'-ft'});
41755 this.pageTb = new Roo.Toolbar(this.footer);
41759 this.footer = this.list.createChild({cls:cls+'-ft'});
41760 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41761 {pageSize: this.pageSize});
41765 if (this.pageTb && this.allowBlank && !this.disableClear) {
41767 this.pageTb.add(new Roo.Toolbar.Fill(), {
41768 cls: 'x-btn-icon x-btn-clear',
41770 handler: function()
41773 _this.clearValue();
41774 _this.onSelect(false, -1);
41779 this.assetHeight += this.footer.getHeight();
41784 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41787 this.view = new Roo.View(this.innerList, this.tpl, {
41790 selectedClass: this.selectedClass
41793 this.view.on('click', this.onViewClick, this);
41795 this.store.on('beforeload', this.onBeforeLoad, this);
41796 this.store.on('load', this.onLoad, this);
41797 this.store.on('loadexception', this.onLoadException, this);
41799 if(this.resizable){
41800 this.resizer = new Roo.Resizable(this.list, {
41801 pinned:true, handles:'se'
41803 this.resizer.on('resize', function(r, w, h){
41804 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41805 this.listWidth = w;
41806 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41807 this.restrictHeight();
41809 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41811 if(!this.editable){
41812 this.editable = true;
41813 this.setEditable(false);
41817 if (typeof(this.events.add.listeners) != 'undefined') {
41819 this.addicon = this.wrap.createChild(
41820 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41822 this.addicon.on('click', function(e) {
41823 this.fireEvent('add', this);
41826 if (typeof(this.events.edit.listeners) != 'undefined') {
41828 this.editicon = this.wrap.createChild(
41829 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41830 if (this.addicon) {
41831 this.editicon.setStyle('margin-left', '40px');
41833 this.editicon.on('click', function(e) {
41835 // we fire even if inothing is selected..
41836 this.fireEvent('edit', this, this.lastData );
41846 initEvents : function(){
41847 Roo.form.ComboBox.superclass.initEvents.call(this);
41849 this.keyNav = new Roo.KeyNav(this.el, {
41850 "up" : function(e){
41851 this.inKeyMode = true;
41855 "down" : function(e){
41856 if(!this.isExpanded()){
41857 this.onTriggerClick();
41859 this.inKeyMode = true;
41864 "enter" : function(e){
41865 this.onViewClick();
41869 "esc" : function(e){
41873 "tab" : function(e){
41874 this.onViewClick(false);
41875 this.fireEvent("specialkey", this, e);
41881 doRelay : function(foo, bar, hname){
41882 if(hname == 'down' || this.scope.isExpanded()){
41883 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41890 this.queryDelay = Math.max(this.queryDelay || 10,
41891 this.mode == 'local' ? 10 : 250);
41892 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41893 if(this.typeAhead){
41894 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41896 if(this.editable !== false){
41897 this.el.on("keyup", this.onKeyUp, this);
41899 if(this.forceSelection){
41900 this.on('blur', this.doForce, this);
41904 onDestroy : function(){
41906 this.view.setStore(null);
41907 this.view.el.removeAllListeners();
41908 this.view.el.remove();
41909 this.view.purgeListeners();
41912 this.list.destroy();
41915 this.store.un('beforeload', this.onBeforeLoad, this);
41916 this.store.un('load', this.onLoad, this);
41917 this.store.un('loadexception', this.onLoadException, this);
41919 Roo.form.ComboBox.superclass.onDestroy.call(this);
41923 fireKey : function(e){
41924 if(e.isNavKeyPress() && !this.list.isVisible()){
41925 this.fireEvent("specialkey", this, e);
41930 onResize: function(w, h){
41931 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41933 if(typeof w != 'number'){
41934 // we do not handle it!?!?
41937 var tw = this.trigger.getWidth();
41938 tw += this.addicon ? this.addicon.getWidth() : 0;
41939 tw += this.editicon ? this.editicon.getWidth() : 0;
41941 this.el.setWidth( this.adjustWidth('input', x));
41943 this.trigger.setStyle('left', x+'px');
41945 if(this.list && this.listWidth === undefined){
41946 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41947 this.list.setWidth(lw);
41948 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41956 * Allow or prevent the user from directly editing the field text. If false is passed,
41957 * the user will only be able to select from the items defined in the dropdown list. This method
41958 * is the runtime equivalent of setting the 'editable' config option at config time.
41959 * @param {Boolean} value True to allow the user to directly edit the field text
41961 setEditable : function(value){
41962 if(value == this.editable){
41965 this.editable = value;
41967 this.el.dom.setAttribute('readOnly', true);
41968 this.el.on('mousedown', this.onTriggerClick, this);
41969 this.el.addClass('x-combo-noedit');
41971 this.el.dom.setAttribute('readOnly', false);
41972 this.el.un('mousedown', this.onTriggerClick, this);
41973 this.el.removeClass('x-combo-noedit');
41978 onBeforeLoad : function(){
41979 if(!this.hasFocus){
41982 this.innerList.update(this.loadingText ?
41983 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41984 this.restrictHeight();
41985 this.selectedIndex = -1;
41989 onLoad : function(){
41990 if(!this.hasFocus){
41993 if(this.store.getCount() > 0){
41995 this.restrictHeight();
41996 if(this.lastQuery == this.allQuery){
41998 this.el.dom.select();
42000 if(!this.selectByValue(this.value, true)){
42001 this.select(0, true);
42005 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
42006 this.taTask.delay(this.typeAheadDelay);
42010 this.onEmptyResults();
42015 onLoadException : function()
42018 Roo.log(this.store.reader.jsonData);
42019 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
42020 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
42026 onTypeAhead : function(){
42027 if(this.store.getCount() > 0){
42028 var r = this.store.getAt(0);
42029 var newValue = r.data[this.displayField];
42030 var len = newValue.length;
42031 var selStart = this.getRawValue().length;
42032 if(selStart != len){
42033 this.setRawValue(newValue);
42034 this.selectText(selStart, newValue.length);
42040 onSelect : function(record, index){
42041 if(this.fireEvent('beforeselect', this, record, index) !== false){
42042 this.setFromData(index > -1 ? record.data : false);
42044 this.fireEvent('select', this, record, index);
42049 * Returns the currently selected field value or empty string if no value is set.
42050 * @return {String} value The selected value
42052 getValue : function(){
42053 if(this.valueField){
42054 return typeof this.value != 'undefined' ? this.value : '';
42056 return Roo.form.ComboBox.superclass.getValue.call(this);
42060 * Clears any text/value currently set in the field
42062 clearValue : function(){
42063 if(this.hiddenField){
42064 this.hiddenField.value = '';
42067 this.setRawValue('');
42068 this.lastSelectionText = '';
42073 * Sets the specified value into the field. If the value finds a match, the corresponding record text
42074 * will be displayed in the field. If the value does not match the data value of an existing item,
42075 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
42076 * Otherwise the field will be blank (although the value will still be set).
42077 * @param {String} value The value to match
42079 setValue : function(v){
42081 if(this.valueField){
42082 var r = this.findRecord(this.valueField, v);
42084 text = r.data[this.displayField];
42085 }else if(this.valueNotFoundText !== undefined){
42086 text = this.valueNotFoundText;
42089 this.lastSelectionText = text;
42090 if(this.hiddenField){
42091 this.hiddenField.value = v;
42093 Roo.form.ComboBox.superclass.setValue.call(this, text);
42097 * @property {Object} the last set data for the element
42102 * Sets the value of the field based on a object which is related to the record format for the store.
42103 * @param {Object} value the value to set as. or false on reset?
42105 setFromData : function(o){
42106 var dv = ''; // display value
42107 var vv = ''; // value value..
42109 if (this.displayField) {
42110 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
42112 // this is an error condition!!!
42113 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
42116 if(this.valueField){
42117 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
42119 if(this.hiddenField){
42120 this.hiddenField.value = vv;
42122 this.lastSelectionText = dv;
42123 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42127 // no hidden field.. - we store the value in 'value', but still display
42128 // display field!!!!
42129 this.lastSelectionText = dv;
42130 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42136 reset : function(){
42137 // overridden so that last data is reset..
42138 this.setValue(this.resetValue);
42139 this.originalValue = this.getValue();
42140 this.clearInvalid();
42141 this.lastData = false;
42143 this.view.clearSelections();
42147 findRecord : function(prop, value){
42149 if(this.store.getCount() > 0){
42150 this.store.each(function(r){
42151 if(r.data[prop] == value){
42161 getName: function()
42163 // returns hidden if it's set..
42164 if (!this.rendered) {return ''};
42165 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42169 onViewMove : function(e, t){
42170 this.inKeyMode = false;
42174 onViewOver : function(e, t){
42175 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42178 var item = this.view.findItemFromChild(t);
42180 var index = this.view.indexOf(item);
42181 this.select(index, false);
42186 onViewClick : function(doFocus)
42188 var index = this.view.getSelectedIndexes()[0];
42189 var r = this.store.getAt(index);
42191 this.onSelect(r, index);
42193 if(doFocus !== false && !this.blockFocus){
42199 restrictHeight : function(){
42200 this.innerList.dom.style.height = '';
42201 var inner = this.innerList.dom;
42202 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42203 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42204 this.list.beginUpdate();
42205 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42206 this.list.alignTo(this.el, this.listAlign);
42207 this.list.endUpdate();
42211 onEmptyResults : function(){
42216 * Returns true if the dropdown list is expanded, else false.
42218 isExpanded : function(){
42219 return this.list.isVisible();
42223 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42224 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42225 * @param {String} value The data value of the item to select
42226 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42227 * selected item if it is not currently in view (defaults to true)
42228 * @return {Boolean} True if the value matched an item in the list, else false
42230 selectByValue : function(v, scrollIntoView){
42231 if(v !== undefined && v !== null){
42232 var r = this.findRecord(this.valueField || this.displayField, v);
42234 this.select(this.store.indexOf(r), scrollIntoView);
42242 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42243 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42244 * @param {Number} index The zero-based index of the list item to select
42245 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42246 * selected item if it is not currently in view (defaults to true)
42248 select : function(index, scrollIntoView){
42249 this.selectedIndex = index;
42250 this.view.select(index);
42251 if(scrollIntoView !== false){
42252 var el = this.view.getNode(index);
42254 this.innerList.scrollChildIntoView(el, false);
42260 selectNext : function(){
42261 var ct = this.store.getCount();
42263 if(this.selectedIndex == -1){
42265 }else if(this.selectedIndex < ct-1){
42266 this.select(this.selectedIndex+1);
42272 selectPrev : function(){
42273 var ct = this.store.getCount();
42275 if(this.selectedIndex == -1){
42277 }else if(this.selectedIndex != 0){
42278 this.select(this.selectedIndex-1);
42284 onKeyUp : function(e){
42285 if(this.editable !== false && !e.isSpecialKey()){
42286 this.lastKey = e.getKey();
42287 this.dqTask.delay(this.queryDelay);
42292 validateBlur : function(){
42293 return !this.list || !this.list.isVisible();
42297 initQuery : function(){
42298 this.doQuery(this.getRawValue());
42302 doForce : function(){
42303 if(this.el.dom.value.length > 0){
42304 this.el.dom.value =
42305 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42311 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42312 * query allowing the query action to be canceled if needed.
42313 * @param {String} query The SQL query to execute
42314 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42315 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42316 * saved in the current store (defaults to false)
42318 doQuery : function(q, forceAll){
42319 if(q === undefined || q === null){
42324 forceAll: forceAll,
42328 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42332 forceAll = qe.forceAll;
42333 if(forceAll === true || (q.length >= this.minChars)){
42334 if(this.lastQuery != q || this.alwaysQuery){
42335 this.lastQuery = q;
42336 if(this.mode == 'local'){
42337 this.selectedIndex = -1;
42339 this.store.clearFilter();
42341 this.store.filter(this.displayField, q);
42345 this.store.baseParams[this.queryParam] = q;
42347 params: this.getParams(q)
42352 this.selectedIndex = -1;
42359 getParams : function(q){
42361 //p[this.queryParam] = q;
42364 p.limit = this.pageSize;
42370 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42372 collapse : function(){
42373 if(!this.isExpanded()){
42377 Roo.get(document).un('mousedown', this.collapseIf, this);
42378 Roo.get(document).un('mousewheel', this.collapseIf, this);
42379 if (!this.editable) {
42380 Roo.get(document).un('keydown', this.listKeyPress, this);
42382 this.fireEvent('collapse', this);
42386 collapseIf : function(e){
42387 if(!e.within(this.wrap) && !e.within(this.list)){
42393 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42395 expand : function(){
42396 if(this.isExpanded() || !this.hasFocus){
42399 this.list.alignTo(this.el, this.listAlign);
42401 Roo.get(document).on('mousedown', this.collapseIf, this);
42402 Roo.get(document).on('mousewheel', this.collapseIf, this);
42403 if (!this.editable) {
42404 Roo.get(document).on('keydown', this.listKeyPress, this);
42407 this.fireEvent('expand', this);
42411 // Implements the default empty TriggerField.onTriggerClick function
42412 onTriggerClick : function(){
42416 if(this.isExpanded()){
42418 if (!this.blockFocus) {
42423 this.hasFocus = true;
42424 if(this.triggerAction == 'all') {
42425 this.doQuery(this.allQuery, true);
42427 this.doQuery(this.getRawValue());
42429 if (!this.blockFocus) {
42434 listKeyPress : function(e)
42436 //Roo.log('listkeypress');
42437 // scroll to first matching element based on key pres..
42438 if (e.isSpecialKey()) {
42441 var k = String.fromCharCode(e.getKey()).toUpperCase();
42444 var csel = this.view.getSelectedNodes();
42445 var cselitem = false;
42447 var ix = this.view.indexOf(csel[0]);
42448 cselitem = this.store.getAt(ix);
42449 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42455 this.store.each(function(v) {
42457 // start at existing selection.
42458 if (cselitem.id == v.id) {
42464 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42465 match = this.store.indexOf(v);
42470 if (match === false) {
42471 return true; // no more action?
42474 this.view.select(match);
42475 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42476 sn.scrollIntoView(sn.dom.parentNode, false);
42480 * @cfg {Boolean} grow
42484 * @cfg {Number} growMin
42488 * @cfg {Number} growMax
42496 * Copyright(c) 2010-2012, Roo J Solutions Limited
42503 * @class Roo.form.ComboBoxArray
42504 * @extends Roo.form.TextField
42505 * A facebook style adder... for lists of email / people / countries etc...
42506 * pick multiple items from a combo box, and shows each one.
42508 * Fred [x] Brian [x] [Pick another |v]
42511 * For this to work: it needs various extra information
42512 * - normal combo problay has
42514 * + displayField, valueField
42516 * For our purpose...
42519 * If we change from 'extends' to wrapping...
42526 * Create a new ComboBoxArray.
42527 * @param {Object} config Configuration options
42531 Roo.form.ComboBoxArray = function(config)
42535 * @event beforeremove
42536 * Fires before remove the value from the list
42537 * @param {Roo.form.ComboBoxArray} _self This combo box array
42538 * @param {Roo.form.ComboBoxArray.Item} item removed item
42540 'beforeremove' : true,
42543 * Fires when remove the value from the list
42544 * @param {Roo.form.ComboBoxArray} _self This combo box array
42545 * @param {Roo.form.ComboBoxArray.Item} item removed item
42552 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42554 this.items = new Roo.util.MixedCollection(false);
42556 // construct the child combo...
42566 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42569 * @cfg {Roo.form.ComboBox} combo [required] The combo box that is wrapped
42574 // behavies liek a hiddne field
42575 inputType: 'hidden',
42577 * @cfg {Number} width The width of the box that displays the selected element
42584 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42588 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42590 hiddenName : false,
42592 * @cfg {String} seperator The value seperator normally ','
42596 // private the array of items that are displayed..
42598 // private - the hidden field el.
42600 // private - the filed el..
42603 //validateValue : function() { return true; }, // all values are ok!
42604 //onAddClick: function() { },
42606 onRender : function(ct, position)
42609 // create the standard hidden element
42610 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42613 // give fake names to child combo;
42614 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42615 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42617 this.combo = Roo.factory(this.combo, Roo.form);
42618 this.combo.onRender(ct, position);
42619 if (typeof(this.combo.width) != 'undefined') {
42620 this.combo.onResize(this.combo.width,0);
42623 this.combo.initEvents();
42625 // assigned so form know we need to do this..
42626 this.store = this.combo.store;
42627 this.valueField = this.combo.valueField;
42628 this.displayField = this.combo.displayField ;
42631 this.combo.wrap.addClass('x-cbarray-grp');
42633 var cbwrap = this.combo.wrap.createChild(
42634 {tag: 'div', cls: 'x-cbarray-cb'},
42639 this.hiddenEl = this.combo.wrap.createChild({
42640 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42642 this.el = this.combo.wrap.createChild({
42643 tag: 'input', type:'hidden' , name: this.name, value : ''
42645 // this.el.dom.removeAttribute("name");
42648 this.outerWrap = this.combo.wrap;
42649 this.wrap = cbwrap;
42651 this.outerWrap.setWidth(this.width);
42652 this.outerWrap.dom.removeChild(this.el.dom);
42654 this.wrap.dom.appendChild(this.el.dom);
42655 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42656 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42658 this.combo.trigger.setStyle('position','relative');
42659 this.combo.trigger.setStyle('left', '0px');
42660 this.combo.trigger.setStyle('top', '2px');
42662 this.combo.el.setStyle('vertical-align', 'text-bottom');
42664 //this.trigger.setStyle('vertical-align', 'top');
42666 // this should use the code from combo really... on('add' ....)
42670 this.adder = this.outerWrap.createChild(
42671 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42673 this.adder.on('click', function(e) {
42674 _t.fireEvent('adderclick', this, e);
42678 //this.adder.on('click', this.onAddClick, _t);
42681 this.combo.on('select', function(cb, rec, ix) {
42682 this.addItem(rec.data);
42685 cb.el.dom.value = '';
42686 //cb.lastData = rec.data;
42695 getName: function()
42697 // returns hidden if it's set..
42698 if (!this.rendered) {return ''};
42699 return this.hiddenName ? this.hiddenName : this.name;
42704 onResize: function(w, h){
42707 // not sure if this is needed..
42708 //this.combo.onResize(w,h);
42710 if(typeof w != 'number'){
42711 // we do not handle it!?!?
42714 var tw = this.combo.trigger.getWidth();
42715 tw += this.addicon ? this.addicon.getWidth() : 0;
42716 tw += this.editicon ? this.editicon.getWidth() : 0;
42718 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42720 this.combo.trigger.setStyle('left', '0px');
42722 if(this.list && this.listWidth === undefined){
42723 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42724 this.list.setWidth(lw);
42725 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42732 addItem: function(rec)
42734 var valueField = this.combo.valueField;
42735 var displayField = this.combo.displayField;
42737 if (this.items.indexOfKey(rec[valueField]) > -1) {
42738 //console.log("GOT " + rec.data.id);
42742 var x = new Roo.form.ComboBoxArray.Item({
42743 //id : rec[this.idField],
42745 displayField : displayField ,
42746 tipField : displayField ,
42750 this.items.add(rec[valueField],x);
42751 // add it before the element..
42752 this.updateHiddenEl();
42753 x.render(this.outerWrap, this.wrap.dom);
42754 // add the image handler..
42757 updateHiddenEl : function()
42760 if (!this.hiddenEl) {
42764 var idField = this.combo.valueField;
42766 this.items.each(function(f) {
42767 ar.push(f.data[idField]);
42769 this.hiddenEl.dom.value = ar.join(this.seperator);
42775 this.items.clear();
42777 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42781 this.el.dom.value = '';
42782 if (this.hiddenEl) {
42783 this.hiddenEl.dom.value = '';
42787 getValue: function()
42789 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42791 setValue: function(v) // not a valid action - must use addItems..
42796 if (this.store.isLocal && (typeof(v) == 'string')) {
42797 // then we can use the store to find the values..
42798 // comma seperated at present.. this needs to allow JSON based encoding..
42799 this.hiddenEl.value = v;
42801 Roo.each(v.split(this.seperator), function(k) {
42802 Roo.log("CHECK " + this.valueField + ',' + k);
42803 var li = this.store.query(this.valueField, k);
42808 add[this.valueField] = k;
42809 add[this.displayField] = li.item(0).data[this.displayField];
42815 if (typeof(v) == 'object' ) {
42816 // then let's assume it's an array of objects..
42817 Roo.each(v, function(l) {
42819 if (typeof(l) == 'string') {
42821 add[this.valueField] = l;
42822 add[this.displayField] = l
42831 setFromData: function(v)
42833 // this recieves an object, if setValues is called.
42835 this.el.dom.value = v[this.displayField];
42836 this.hiddenEl.dom.value = v[this.valueField];
42837 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42840 var kv = v[this.valueField];
42841 var dv = v[this.displayField];
42842 kv = typeof(kv) != 'string' ? '' : kv;
42843 dv = typeof(dv) != 'string' ? '' : dv;
42846 var keys = kv.split(this.seperator);
42847 var display = dv.split(this.seperator);
42848 for (var i = 0 ; i < keys.length; i++) {
42850 add[this.valueField] = keys[i];
42851 add[this.displayField] = display[i];
42859 * Validates the combox array value
42860 * @return {Boolean} True if the value is valid, else false
42862 validate : function(){
42863 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42864 this.clearInvalid();
42870 validateValue : function(value){
42871 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42879 isDirty : function() {
42880 if(this.disabled) {
42885 var d = Roo.decode(String(this.originalValue));
42887 return String(this.getValue()) !== String(this.originalValue);
42890 var originalValue = [];
42892 for (var i = 0; i < d.length; i++){
42893 originalValue.push(d[i][this.valueField]);
42896 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42905 * @class Roo.form.ComboBoxArray.Item
42906 * @extends Roo.BoxComponent
42907 * A selected item in the list
42908 * Fred [x] Brian [x] [Pick another |v]
42911 * Create a new item.
42912 * @param {Object} config Configuration options
42915 Roo.form.ComboBoxArray.Item = function(config) {
42916 config.id = Roo.id();
42917 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42920 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42923 displayField : false,
42927 defaultAutoCreate : {
42929 cls: 'x-cbarray-item',
42936 src : Roo.BLANK_IMAGE_URL ,
42944 onRender : function(ct, position)
42946 Roo.form.Field.superclass.onRender.call(this, ct, position);
42949 var cfg = this.getAutoCreate();
42950 this.el = ct.createChild(cfg, position);
42953 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42955 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42956 this.cb.renderer(this.data) :
42957 String.format('{0}',this.data[this.displayField]);
42960 this.el.child('div').dom.setAttribute('qtip',
42961 String.format('{0}',this.data[this.tipField])
42964 this.el.child('img').on('click', this.remove, this);
42968 remove : function()
42970 if(this.cb.disabled){
42974 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42975 this.cb.items.remove(this);
42976 this.el.child('img').un('click', this.remove, this);
42978 this.cb.updateHiddenEl();
42980 this.cb.fireEvent('remove', this.cb, this);
42985 * RooJS Library 1.1.1
42986 * Copyright(c) 2008-2011 Alan Knowles
42993 * @class Roo.form.ComboNested
42994 * @extends Roo.form.ComboBox
42995 * A combobox for that allows selection of nested items in a list,
43010 * Create a new ComboNested
43011 * @param {Object} config Configuration options
43013 Roo.form.ComboNested = function(config){
43014 Roo.form.ComboCheck.superclass.constructor.call(this, config);
43015 // should verify some data...
43017 // hiddenName = required..
43018 // displayField = required
43019 // valudField == required
43020 var req= [ 'hiddenName', 'displayField', 'valueField' ];
43022 Roo.each(req, function(e) {
43023 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
43024 throw "Roo.form.ComboNested : missing value for: " + e;
43031 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
43034 * @config {Number} max Number of columns to show
43039 list : null, // the outermost div..
43040 innerLists : null, // the
43044 loadingChildren : false,
43046 onRender : function(ct, position)
43048 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
43050 if(this.hiddenName){
43051 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
43053 this.hiddenField.value =
43054 this.hiddenValue !== undefined ? this.hiddenValue :
43055 this.value !== undefined ? this.value : '';
43057 // prevent input submission
43058 this.el.dom.removeAttribute('name');
43064 this.el.dom.setAttribute('autocomplete', 'off');
43067 var cls = 'x-combo-list';
43069 this.list = new Roo.Layer({
43070 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
43073 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
43074 this.list.setWidth(lw);
43075 this.list.swallowEvent('mousewheel');
43076 this.assetHeight = 0;
43079 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
43080 this.assetHeight += this.header.getHeight();
43082 this.innerLists = [];
43085 for (var i =0 ; i < this.maxColumns; i++) {
43086 this.onRenderList( cls, i);
43089 // always needs footer, as we are going to have an 'OK' button.
43090 this.footer = this.list.createChild({cls:cls+'-ft'});
43091 this.pageTb = new Roo.Toolbar(this.footer);
43096 handler: function()
43102 if ( this.allowBlank && !this.disableClear) {
43104 this.pageTb.add(new Roo.Toolbar.Fill(), {
43105 cls: 'x-btn-icon x-btn-clear',
43107 handler: function()
43110 _this.clearValue();
43111 _this.onSelect(false, -1);
43116 this.assetHeight += this.footer.getHeight();
43120 onRenderList : function ( cls, i)
43123 var lw = Math.floor(
43124 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43127 this.list.setWidth(lw); // default to '1'
43129 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
43130 //il.on('mouseover', this.onViewOver, this, { list: i });
43131 //il.on('mousemove', this.onViewMove, this, { list: i });
43133 il.setStyle({ 'overflow-x' : 'hidden'});
43136 this.tpl = new Roo.Template({
43137 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
43138 isEmpty: function (value, allValues) {
43140 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
43141 return dl ? 'has-children' : 'no-children'
43146 var store = this.store;
43148 store = new Roo.data.SimpleStore({
43149 //fields : this.store.reader.meta.fields,
43150 reader : this.store.reader,
43154 this.stores[i] = store;
43156 var view = this.views[i] = new Roo.View(
43162 selectedClass: this.selectedClass
43165 view.getEl().setWidth(lw);
43166 view.getEl().setStyle({
43167 position: i < 1 ? 'relative' : 'absolute',
43169 left: (i * lw ) + 'px',
43170 display : i > 0 ? 'none' : 'block'
43172 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
43173 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
43174 //view.on('click', this.onViewClick, this, { list : i });
43176 store.on('beforeload', this.onBeforeLoad, this);
43177 store.on('load', this.onLoad, this, { list : i});
43178 store.on('loadexception', this.onLoadException, this);
43180 // hide the other vies..
43186 restrictHeight : function()
43189 Roo.each(this.innerLists, function(il,i) {
43190 var el = this.views[i].getEl();
43191 el.dom.style.height = '';
43192 var inner = el.dom;
43193 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
43194 // only adjust heights on other ones..
43195 mh = Math.max(h, mh);
43198 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43199 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43206 this.list.beginUpdate();
43207 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43208 this.list.alignTo(this.el, this.listAlign);
43209 this.list.endUpdate();
43214 // -- store handlers..
43216 onBeforeLoad : function()
43218 if(!this.hasFocus){
43221 this.innerLists[0].update(this.loadingText ?
43222 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43223 this.restrictHeight();
43224 this.selectedIndex = -1;
43227 onLoad : function(a,b,c,d)
43229 if (!this.loadingChildren) {
43230 // then we are loading the top level. - hide the children
43231 for (var i = 1;i < this.views.length; i++) {
43232 this.views[i].getEl().setStyle({ display : 'none' });
43234 var lw = Math.floor(
43235 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43238 this.list.setWidth(lw); // default to '1'
43242 if(!this.hasFocus){
43246 if(this.store.getCount() > 0) {
43248 this.restrictHeight();
43250 this.onEmptyResults();
43253 if (!this.loadingChildren) {
43254 this.selectActive();
43257 this.stores[1].loadData([]);
43258 this.stores[2].loadData([]);
43267 onLoadException : function()
43270 Roo.log(this.store.reader.jsonData);
43271 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43272 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43277 // no cleaning of leading spaces on blur here.
43278 cleanLeadingSpace : function(e) { },
43281 onSelectChange : function (view, sels, opts )
43283 var ix = view.getSelectedIndexes();
43285 if (opts.list > this.maxColumns - 2) {
43286 if (view.store.getCount()< 1) {
43287 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43291 // used to clear ?? but if we are loading unselected
43292 this.setFromData(view.store.getAt(ix[0]).data);
43301 // this get's fired when trigger opens..
43302 // this.setFromData({});
43303 var str = this.stores[opts.list+1];
43304 str.data.clear(); // removeall wihtout the fire events..
43308 var rec = view.store.getAt(ix[0]);
43310 this.setFromData(rec.data);
43311 this.fireEvent('select', this, rec, ix[0]);
43313 var lw = Math.floor(
43315 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43316 ) / this.maxColumns
43318 this.loadingChildren = true;
43319 this.stores[opts.list+1].loadDataFromChildren( rec );
43320 this.loadingChildren = false;
43321 var dl = this.stores[opts.list+1]. getTotalCount();
43323 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43325 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43326 for (var i = opts.list+2; i < this.views.length;i++) {
43327 this.views[i].getEl().setStyle({ display : 'none' });
43330 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43331 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43333 if (this.isLoading) {
43334 // this.selectActive(opts.list);
43342 onDoubleClick : function()
43344 this.collapse(); //??
43352 recordToStack : function(store, prop, value, stack)
43354 var cstore = new Roo.data.SimpleStore({
43355 //fields : this.store.reader.meta.fields, // we need array reader.. for
43356 reader : this.store.reader,
43360 var record = false;
43362 if(store.getCount() < 1){
43365 store.each(function(r){
43366 if(r.data[prop] == value){
43371 if (r.data.cn && r.data.cn.length) {
43372 cstore.loadDataFromChildren( r);
43373 var cret = _this.recordToStack(cstore, prop, value, stack);
43374 if (cret !== false) {
43383 if (record == false) {
43386 stack.unshift(srec);
43391 * find the stack of stores that match our value.
43396 selectActive : function ()
43398 // if store is not loaded, then we will need to wait for that to happen first.
43400 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43401 for (var i = 0; i < stack.length; i++ ) {
43402 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43414 * Ext JS Library 1.1.1
43415 * Copyright(c) 2006-2007, Ext JS, LLC.
43417 * Originally Released Under LGPL - original licence link has changed is not relivant.
43420 * <script type="text/javascript">
43423 * @class Roo.form.Checkbox
43424 * @extends Roo.form.Field
43425 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43427 * Creates a new Checkbox
43428 * @param {Object} config Configuration options
43430 Roo.form.Checkbox = function(config){
43431 Roo.form.Checkbox.superclass.constructor.call(this, config);
43435 * Fires when the checkbox is checked or unchecked.
43436 * @param {Roo.form.Checkbox} this This checkbox
43437 * @param {Boolean} checked The new checked value
43443 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43445 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43447 focusClass : undefined,
43449 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43451 fieldClass: "x-form-field",
43453 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43457 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43458 * {tag: "input", type: "checkbox", autocomplete: "off"})
43460 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43462 * @cfg {String} boxLabel The text that appears beside the checkbox
43466 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43470 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43472 valueOff: '0', // value when not checked..
43474 actionMode : 'viewEl',
43477 itemCls : 'x-menu-check-item x-form-item',
43478 groupClass : 'x-menu-group-item',
43479 inputType : 'hidden',
43482 inSetChecked: false, // check that we are not calling self...
43484 inputElement: false, // real input element?
43485 basedOn: false, // ????
43487 isFormField: true, // not sure where this is needed!!!!
43489 onResize : function(){
43490 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43491 if(!this.boxLabel){
43492 this.el.alignTo(this.wrap, 'c-c');
43496 initEvents : function(){
43497 Roo.form.Checkbox.superclass.initEvents.call(this);
43498 this.el.on("click", this.onClick, this);
43499 this.el.on("change", this.onClick, this);
43503 getResizeEl : function(){
43507 getPositionEl : function(){
43512 onRender : function(ct, position){
43513 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43515 if(this.inputValue !== undefined){
43516 this.el.dom.value = this.inputValue;
43519 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43520 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43521 var viewEl = this.wrap.createChild({
43522 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43523 this.viewEl = viewEl;
43524 this.wrap.on('click', this.onClick, this);
43526 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43527 this.el.on('propertychange', this.setFromHidden, this); //ie
43532 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43533 // viewEl.on('click', this.onClick, this);
43535 //if(this.checked){
43536 this.setChecked(this.checked);
43538 //this.checked = this.el.dom;
43544 initValue : Roo.emptyFn,
43547 * Returns the checked state of the checkbox.
43548 * @return {Boolean} True if checked, else false
43550 getValue : function(){
43552 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43554 return this.valueOff;
43559 onClick : function(){
43560 if (this.disabled) {
43563 this.setChecked(!this.checked);
43565 //if(this.el.dom.checked != this.checked){
43566 // this.setValue(this.el.dom.checked);
43571 * Sets the checked state of the checkbox.
43572 * On is always based on a string comparison between inputValue and the param.
43573 * @param {Boolean/String} value - the value to set
43574 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43576 setValue : function(v,suppressEvent){
43579 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43580 //if(this.el && this.el.dom){
43581 // this.el.dom.checked = this.checked;
43582 // this.el.dom.defaultChecked = this.checked;
43584 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43585 //this.fireEvent("check", this, this.checked);
43588 setChecked : function(state,suppressEvent)
43590 if (this.inSetChecked) {
43591 this.checked = state;
43597 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43599 this.checked = state;
43600 if(suppressEvent !== true){
43601 this.fireEvent('check', this, state);
43603 this.inSetChecked = true;
43604 this.el.dom.value = state ? this.inputValue : this.valueOff;
43605 this.inSetChecked = false;
43608 // handle setting of hidden value by some other method!!?!?
43609 setFromHidden: function()
43614 //console.log("SET FROM HIDDEN");
43615 //alert('setFrom hidden');
43616 this.setValue(this.el.dom.value);
43619 onDestroy : function()
43622 Roo.get(this.viewEl).remove();
43625 Roo.form.Checkbox.superclass.onDestroy.call(this);
43628 setBoxLabel : function(str)
43630 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43635 * Ext JS Library 1.1.1
43636 * Copyright(c) 2006-2007, Ext JS, LLC.
43638 * Originally Released Under LGPL - original licence link has changed is not relivant.
43641 * <script type="text/javascript">
43645 * @class Roo.form.Radio
43646 * @extends Roo.form.Checkbox
43647 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43648 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43650 * Creates a new Radio
43651 * @param {Object} config Configuration options
43653 Roo.form.Radio = function(){
43654 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43656 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43657 inputType: 'radio',
43660 * If this radio is part of a group, it will return the selected value
43663 getGroupValue : function(){
43664 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43668 onRender : function(ct, position){
43669 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43671 if(this.inputValue !== undefined){
43672 this.el.dom.value = this.inputValue;
43675 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43676 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43677 //var viewEl = this.wrap.createChild({
43678 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43679 //this.viewEl = viewEl;
43680 //this.wrap.on('click', this.onClick, this);
43682 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43683 //this.el.on('propertychange', this.setFromHidden, this); //ie
43688 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43689 // viewEl.on('click', this.onClick, this);
43692 this.el.dom.checked = 'checked' ;
43698 });//<script type="text/javascript">
43701 * Based Ext JS Library 1.1.1
43702 * Copyright(c) 2006-2007, Ext JS, LLC.
43708 * @class Roo.HtmlEditorCore
43709 * @extends Roo.Component
43710 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43712 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43715 Roo.HtmlEditorCore = function(config){
43718 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43723 * @event initialize
43724 * Fires when the editor is fully initialized (including the iframe)
43725 * @param {Roo.HtmlEditorCore} this
43730 * Fires when the editor is first receives the focus. Any insertion must wait
43731 * until after this event.
43732 * @param {Roo.HtmlEditorCore} this
43736 * @event beforesync
43737 * Fires before the textarea is updated with content from the editor iframe. Return false
43738 * to cancel the sync.
43739 * @param {Roo.HtmlEditorCore} this
43740 * @param {String} html
43744 * @event beforepush
43745 * Fires before the iframe editor is updated with content from the textarea. Return false
43746 * to cancel the push.
43747 * @param {Roo.HtmlEditorCore} this
43748 * @param {String} html
43753 * Fires when the textarea is updated with content from the editor iframe.
43754 * @param {Roo.HtmlEditorCore} this
43755 * @param {String} html
43760 * Fires when the iframe editor is updated with content from the textarea.
43761 * @param {Roo.HtmlEditorCore} this
43762 * @param {String} html
43767 * @event editorevent
43768 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43769 * @param {Roo.HtmlEditorCore} this
43775 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43777 // defaults : white / black...
43778 this.applyBlacklists();
43785 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43789 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43795 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43800 * @cfg {Number} height (in pixels)
43804 * @cfg {Number} width (in pixels)
43809 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43812 stylesheets: false,
43815 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
43817 allowComments: false,
43821 // private properties
43822 validationEvent : false,
43824 initialized : false,
43826 sourceEditMode : false,
43827 onFocus : Roo.emptyFn,
43829 hideMode:'offsets',
43833 // blacklist + whitelisted elements..
43840 * Protected method that will not generally be called directly. It
43841 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43842 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43844 getDocMarkup : function(){
43848 // inherit styels from page...??
43849 if (this.stylesheets === false) {
43851 Roo.get(document.head).select('style').each(function(node) {
43852 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43855 Roo.get(document.head).select('link').each(function(node) {
43856 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43859 } else if (!this.stylesheets.length) {
43861 st = '<style type="text/css">' +
43862 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43865 for (var i in this.stylesheets) {
43866 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43871 st += '<style type="text/css">' +
43872 'IMG { cursor: pointer } ' +
43875 var cls = 'roo-htmleditor-body';
43877 if(this.bodyCls.length){
43878 cls += ' ' + this.bodyCls;
43881 return '<html><head>' + st +
43882 //<style type="text/css">' +
43883 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43885 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43889 onRender : function(ct, position)
43892 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43893 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43896 this.el.dom.style.border = '0 none';
43897 this.el.dom.setAttribute('tabIndex', -1);
43898 this.el.addClass('x-hidden hide');
43902 if(Roo.isIE){ // fix IE 1px bogus margin
43903 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43907 this.frameId = Roo.id();
43911 var iframe = this.owner.wrap.createChild({
43913 cls: 'form-control', // bootstrap..
43915 name: this.frameId,
43916 frameBorder : 'no',
43917 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43922 this.iframe = iframe.dom;
43924 this.assignDocWin();
43926 this.doc.designMode = 'on';
43929 this.doc.write(this.getDocMarkup());
43933 var task = { // must defer to wait for browser to be ready
43935 //console.log("run task?" + this.doc.readyState);
43936 this.assignDocWin();
43937 if(this.doc.body || this.doc.readyState == 'complete'){
43939 this.doc.designMode="on";
43943 Roo.TaskMgr.stop(task);
43944 this.initEditor.defer(10, this);
43951 Roo.TaskMgr.start(task);
43956 onResize : function(w, h)
43958 Roo.log('resize: ' +w + ',' + h );
43959 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43963 if(typeof w == 'number'){
43965 this.iframe.style.width = w + 'px';
43967 if(typeof h == 'number'){
43969 this.iframe.style.height = h + 'px';
43971 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43978 * Toggles the editor between standard and source edit mode.
43979 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43981 toggleSourceEdit : function(sourceEditMode){
43983 this.sourceEditMode = sourceEditMode === true;
43985 if(this.sourceEditMode){
43987 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43990 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43991 //this.iframe.className = '';
43994 //this.setSize(this.owner.wrap.getSize());
43995 //this.fireEvent('editmodechange', this, this.sourceEditMode);
44002 * Protected method that will not generally be called directly. If you need/want
44003 * custom HTML cleanup, this is the method you should override.
44004 * @param {String} html The HTML to be cleaned
44005 * return {String} The cleaned HTML
44007 cleanHtml : function(html){
44008 html = String(html);
44009 if(html.length > 5){
44010 if(Roo.isSafari){ // strip safari nonsense
44011 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
44014 if(html == ' '){
44021 * HTML Editor -> Textarea
44022 * Protected method that will not generally be called directly. Syncs the contents
44023 * of the editor iframe with the textarea.
44025 syncValue : function(){
44026 if(this.initialized){
44027 var bd = (this.doc.body || this.doc.documentElement);
44028 //this.cleanUpPaste(); -- this is done else where and causes havoc..
44029 var html = bd.innerHTML;
44031 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
44032 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
44034 html = '<div style="'+m[0]+'">' + html + '</div>';
44037 html = this.cleanHtml(html);
44038 // fix up the special chars.. normaly like back quotes in word...
44039 // however we do not want to do this with chinese..
44040 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
44042 var cc = match.charCodeAt();
44044 // Get the character value, handling surrogate pairs
44045 if (match.length == 2) {
44046 // It's a surrogate pair, calculate the Unicode code point
44047 var high = match.charCodeAt(0) - 0xD800;
44048 var low = match.charCodeAt(1) - 0xDC00;
44049 cc = (high * 0x400) + low + 0x10000;
44051 (cc >= 0x4E00 && cc < 0xA000 ) ||
44052 (cc >= 0x3400 && cc < 0x4E00 ) ||
44053 (cc >= 0xf900 && cc < 0xfb00 )
44058 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
44059 return "&#" + cc + ";";
44066 if(this.owner.fireEvent('beforesync', this, html) !== false){
44067 this.el.dom.value = html;
44068 this.owner.fireEvent('sync', this, html);
44074 * Protected method that will not generally be called directly. Pushes the value of the textarea
44075 * into the iframe editor.
44077 pushValue : function(){
44078 if(this.initialized){
44079 var v = this.el.dom.value.trim();
44081 // if(v.length < 1){
44085 if(this.owner.fireEvent('beforepush', this, v) !== false){
44086 var d = (this.doc.body || this.doc.documentElement);
44088 this.cleanUpPaste();
44089 this.el.dom.value = d.innerHTML;
44090 this.owner.fireEvent('push', this, v);
44096 deferFocus : function(){
44097 this.focus.defer(10, this);
44101 focus : function(){
44102 if(this.win && !this.sourceEditMode){
44109 assignDocWin: function()
44111 var iframe = this.iframe;
44114 this.doc = iframe.contentWindow.document;
44115 this.win = iframe.contentWindow;
44117 // if (!Roo.get(this.frameId)) {
44120 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44121 // this.win = Roo.get(this.frameId).dom.contentWindow;
44123 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
44127 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44128 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
44133 initEditor : function(){
44134 //console.log("INIT EDITOR");
44135 this.assignDocWin();
44139 this.doc.designMode="on";
44141 this.doc.write(this.getDocMarkup());
44144 var dbody = (this.doc.body || this.doc.documentElement);
44145 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
44146 // this copies styles from the containing element into thsi one..
44147 // not sure why we need all of this..
44148 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
44150 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
44151 //ss['background-attachment'] = 'fixed'; // w3c
44152 dbody.bgProperties = 'fixed'; // ie
44153 //Roo.DomHelper.applyStyles(dbody, ss);
44154 Roo.EventManager.on(this.doc, {
44155 //'mousedown': this.onEditorEvent,
44156 'mouseup': this.onEditorEvent,
44157 'dblclick': this.onEditorEvent,
44158 'click': this.onEditorEvent,
44159 'keyup': this.onEditorEvent,
44164 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
44166 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
44167 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
44169 this.initialized = true;
44171 this.owner.fireEvent('initialize', this);
44176 onDestroy : function(){
44182 //for (var i =0; i < this.toolbars.length;i++) {
44183 // // fixme - ask toolbars for heights?
44184 // this.toolbars[i].onDestroy();
44187 //this.wrap.dom.innerHTML = '';
44188 //this.wrap.remove();
44193 onFirstFocus : function(){
44195 this.assignDocWin();
44198 this.activated = true;
44201 if(Roo.isGecko){ // prevent silly gecko errors
44203 var s = this.win.getSelection();
44204 if(!s.focusNode || s.focusNode.nodeType != 3){
44205 var r = s.getRangeAt(0);
44206 r.selectNodeContents((this.doc.body || this.doc.documentElement));
44211 this.execCmd('useCSS', true);
44212 this.execCmd('styleWithCSS', false);
44215 this.owner.fireEvent('activate', this);
44219 adjustFont: function(btn){
44220 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44221 //if(Roo.isSafari){ // safari
44224 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44225 if(Roo.isSafari){ // safari
44226 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44227 v = (v < 10) ? 10 : v;
44228 v = (v > 48) ? 48 : v;
44229 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44234 v = Math.max(1, v+adjust);
44236 this.execCmd('FontSize', v );
44239 onEditorEvent : function(e)
44241 this.owner.fireEvent('editorevent', this, e);
44242 // this.updateToolbar();
44243 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44246 insertTag : function(tg)
44248 // could be a bit smarter... -> wrap the current selected tRoo..
44249 if (tg.toLowerCase() == 'span' ||
44250 tg.toLowerCase() == 'code' ||
44251 tg.toLowerCase() == 'sup' ||
44252 tg.toLowerCase() == 'sub'
44255 range = this.createRange(this.getSelection());
44256 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44257 wrappingNode.appendChild(range.extractContents());
44258 range.insertNode(wrappingNode);
44265 this.execCmd("formatblock", tg);
44269 insertText : function(txt)
44273 var range = this.createRange();
44274 range.deleteContents();
44275 //alert(Sender.getAttribute('label'));
44277 range.insertNode(this.doc.createTextNode(txt));
44283 * Executes a Midas editor command on the editor document and performs necessary focus and
44284 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44285 * @param {String} cmd The Midas command
44286 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44288 relayCmd : function(cmd, value){
44290 this.execCmd(cmd, value);
44291 this.owner.fireEvent('editorevent', this);
44292 //this.updateToolbar();
44293 this.owner.deferFocus();
44297 * Executes a Midas editor command directly on the editor document.
44298 * For visual commands, you should use {@link #relayCmd} instead.
44299 * <b>This should only be called after the editor is initialized.</b>
44300 * @param {String} cmd The Midas command
44301 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44303 execCmd : function(cmd, value){
44304 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44311 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44313 * @param {String} text | dom node..
44315 insertAtCursor : function(text)
44318 if(!this.activated){
44324 var r = this.doc.selection.createRange();
44335 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44339 // from jquery ui (MIT licenced)
44341 var win = this.win;
44343 if (win.getSelection && win.getSelection().getRangeAt) {
44344 range = win.getSelection().getRangeAt(0);
44345 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44346 range.insertNode(node);
44347 } else if (win.document.selection && win.document.selection.createRange) {
44348 // no firefox support
44349 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44350 win.document.selection.createRange().pasteHTML(txt);
44352 // no firefox support
44353 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44354 this.execCmd('InsertHTML', txt);
44363 mozKeyPress : function(e){
44365 var c = e.getCharCode(), cmd;
44368 c = String.fromCharCode(c).toLowerCase();
44382 this.cleanUpPaste.defer(100, this);
44390 e.preventDefault();
44398 fixKeys : function(){ // load time branching for fastest keydown performance
44400 return function(e){
44401 var k = e.getKey(), r;
44404 r = this.doc.selection.createRange();
44407 r.pasteHTML('    ');
44414 r = this.doc.selection.createRange();
44416 var target = r.parentElement();
44417 if(!target || target.tagName.toLowerCase() != 'li'){
44419 r.pasteHTML('<br />');
44425 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44426 this.cleanUpPaste.defer(100, this);
44432 }else if(Roo.isOpera){
44433 return function(e){
44434 var k = e.getKey();
44438 this.execCmd('InsertHTML','    ');
44441 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44442 this.cleanUpPaste.defer(100, this);
44447 }else if(Roo.isSafari){
44448 return function(e){
44449 var k = e.getKey();
44453 this.execCmd('InsertText','\t');
44457 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44458 this.cleanUpPaste.defer(100, this);
44466 getAllAncestors: function()
44468 var p = this.getSelectedNode();
44471 a.push(p); // push blank onto stack..
44472 p = this.getParentElement();
44476 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44480 a.push(this.doc.body);
44484 lastSelNode : false,
44487 getSelection : function()
44489 this.assignDocWin();
44490 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44493 getSelectedNode: function()
44495 // this may only work on Gecko!!!
44497 // should we cache this!!!!
44502 var range = this.createRange(this.getSelection()).cloneRange();
44505 var parent = range.parentElement();
44507 var testRange = range.duplicate();
44508 testRange.moveToElementText(parent);
44509 if (testRange.inRange(range)) {
44512 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44515 parent = parent.parentElement;
44520 // is ancestor a text element.
44521 var ac = range.commonAncestorContainer;
44522 if (ac.nodeType == 3) {
44523 ac = ac.parentNode;
44526 var ar = ac.childNodes;
44529 var other_nodes = [];
44530 var has_other_nodes = false;
44531 for (var i=0;i<ar.length;i++) {
44532 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44535 // fullly contained node.
44537 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44542 // probably selected..
44543 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44544 other_nodes.push(ar[i]);
44548 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44553 has_other_nodes = true;
44555 if (!nodes.length && other_nodes.length) {
44556 nodes= other_nodes;
44558 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44564 createRange: function(sel)
44566 // this has strange effects when using with
44567 // top toolbar - not sure if it's a great idea.
44568 //this.editor.contentWindow.focus();
44569 if (typeof sel != "undefined") {
44571 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44573 return this.doc.createRange();
44576 return this.doc.createRange();
44579 getParentElement: function()
44582 this.assignDocWin();
44583 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44585 var range = this.createRange(sel);
44588 var p = range.commonAncestorContainer;
44589 while (p.nodeType == 3) { // text node
44600 * Range intersection.. the hard stuff...
44604 * [ -- selected range --- ]
44608 * if end is before start or hits it. fail.
44609 * if start is after end or hits it fail.
44611 * if either hits (but other is outside. - then it's not
44617 // @see http://www.thismuchiknow.co.uk/?p=64.
44618 rangeIntersectsNode : function(range, node)
44620 var nodeRange = node.ownerDocument.createRange();
44622 nodeRange.selectNode(node);
44624 nodeRange.selectNodeContents(node);
44627 var rangeStartRange = range.cloneRange();
44628 rangeStartRange.collapse(true);
44630 var rangeEndRange = range.cloneRange();
44631 rangeEndRange.collapse(false);
44633 var nodeStartRange = nodeRange.cloneRange();
44634 nodeStartRange.collapse(true);
44636 var nodeEndRange = nodeRange.cloneRange();
44637 nodeEndRange.collapse(false);
44639 return rangeStartRange.compareBoundaryPoints(
44640 Range.START_TO_START, nodeEndRange) == -1 &&
44641 rangeEndRange.compareBoundaryPoints(
44642 Range.START_TO_START, nodeStartRange) == 1;
44646 rangeCompareNode : function(range, node)
44648 var nodeRange = node.ownerDocument.createRange();
44650 nodeRange.selectNode(node);
44652 nodeRange.selectNodeContents(node);
44656 range.collapse(true);
44658 nodeRange.collapse(true);
44660 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44661 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44663 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44665 var nodeIsBefore = ss == 1;
44666 var nodeIsAfter = ee == -1;
44668 if (nodeIsBefore && nodeIsAfter) {
44671 if (!nodeIsBefore && nodeIsAfter) {
44672 return 1; //right trailed.
44675 if (nodeIsBefore && !nodeIsAfter) {
44676 return 2; // left trailed.
44682 // private? - in a new class?
44683 cleanUpPaste : function()
44685 // cleans up the whole document..
44686 Roo.log('cleanuppaste');
44688 this.cleanUpChildren(this.doc.body);
44689 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44690 if (clean != this.doc.body.innerHTML) {
44691 this.doc.body.innerHTML = clean;
44696 cleanWordChars : function(input) {// change the chars to hex code
44697 var he = Roo.HtmlEditorCore;
44699 var output = input;
44700 Roo.each(he.swapCodes, function(sw) {
44701 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44703 output = output.replace(swapper, sw[1]);
44710 cleanUpChildren : function (n)
44712 if (!n.childNodes.length) {
44715 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44716 this.cleanUpChild(n.childNodes[i]);
44723 cleanUpChild : function (node)
44726 //console.log(node);
44727 if (node.nodeName == "#text") {
44728 // clean up silly Windows -- stuff?
44731 if (node.nodeName == "#comment") {
44732 if (!this.allowComments) {
44733 node.parentNode.removeChild(node);
44735 // clean up silly Windows -- stuff?
44738 var lcname = node.tagName.toLowerCase();
44739 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44740 // whitelist of tags..
44742 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44744 node.parentNode.removeChild(node);
44749 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44751 // spans with no attributes - just remove them..
44752 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44753 remove_keep_children = true;
44756 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44757 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44759 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44760 // remove_keep_children = true;
44763 if (remove_keep_children) {
44764 this.cleanUpChildren(node);
44765 // inserts everything just before this node...
44766 while (node.childNodes.length) {
44767 var cn = node.childNodes[0];
44768 node.removeChild(cn);
44769 node.parentNode.insertBefore(cn, node);
44771 node.parentNode.removeChild(node);
44775 if (!node.attributes || !node.attributes.length) {
44780 this.cleanUpChildren(node);
44784 function cleanAttr(n,v)
44787 if (v.match(/^\./) || v.match(/^\//)) {
44790 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44793 if (v.match(/^#/)) {
44796 if (v.match(/^\{/)) { // allow template editing.
44799 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44800 node.removeAttribute(n);
44804 var cwhite = this.cwhite;
44805 var cblack = this.cblack;
44807 function cleanStyle(n,v)
44809 if (v.match(/expression/)) { //XSS?? should we even bother..
44810 node.removeAttribute(n);
44814 var parts = v.split(/;/);
44817 Roo.each(parts, function(p) {
44818 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44822 var l = p.split(':').shift().replace(/\s+/g,'');
44823 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44825 if ( cwhite.length && cblack.indexOf(l) > -1) {
44826 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44827 //node.removeAttribute(n);
44831 // only allow 'c whitelisted system attributes'
44832 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44833 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44834 //node.removeAttribute(n);
44844 if (clean.length) {
44845 node.setAttribute(n, clean.join(';'));
44847 node.removeAttribute(n);
44853 for (var i = node.attributes.length-1; i > -1 ; i--) {
44854 var a = node.attributes[i];
44857 if (a.name.toLowerCase().substr(0,2)=='on') {
44858 node.removeAttribute(a.name);
44861 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44862 node.removeAttribute(a.name);
44865 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44866 cleanAttr(a.name,a.value); // fixme..
44869 if (a.name == 'style') {
44870 cleanStyle(a.name,a.value);
44873 /// clean up MS crap..
44874 // tecnically this should be a list of valid class'es..
44877 if (a.name == 'class') {
44878 if (a.value.match(/^Mso/)) {
44879 node.removeAttribute('class');
44882 if (a.value.match(/^body$/)) {
44883 node.removeAttribute('class');
44894 this.cleanUpChildren(node);
44900 * Clean up MS wordisms...
44902 cleanWord : function(node)
44905 this.cleanWord(this.doc.body);
44910 node.nodeName == 'SPAN' &&
44911 !node.hasAttributes() &&
44912 node.childNodes.length == 1 &&
44913 node.firstChild.nodeName == "#text"
44915 var textNode = node.firstChild;
44916 node.removeChild(textNode);
44917 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44918 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44920 node.parentNode.insertBefore(textNode, node);
44921 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44922 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44924 node.parentNode.removeChild(node);
44927 if (node.nodeName == "#text") {
44928 // clean up silly Windows -- stuff?
44931 if (node.nodeName == "#comment") {
44932 node.parentNode.removeChild(node);
44933 // clean up silly Windows -- stuff?
44937 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44938 node.parentNode.removeChild(node);
44941 //Roo.log(node.tagName);
44942 // remove - but keep children..
44943 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44944 //Roo.log('-- removed');
44945 while (node.childNodes.length) {
44946 var cn = node.childNodes[0];
44947 node.removeChild(cn);
44948 node.parentNode.insertBefore(cn, node);
44949 // move node to parent - and clean it..
44950 this.cleanWord(cn);
44952 node.parentNode.removeChild(node);
44953 /// no need to iterate chidlren = it's got none..
44954 //this.iterateChildren(node, this.cleanWord);
44958 if (node.className.length) {
44960 var cn = node.className.split(/\W+/);
44962 Roo.each(cn, function(cls) {
44963 if (cls.match(/Mso[a-zA-Z]+/)) {
44968 node.className = cna.length ? cna.join(' ') : '';
44970 node.removeAttribute("class");
44974 if (node.hasAttribute("lang")) {
44975 node.removeAttribute("lang");
44978 if (node.hasAttribute("style")) {
44980 var styles = node.getAttribute("style").split(";");
44982 Roo.each(styles, function(s) {
44983 if (!s.match(/:/)) {
44986 var kv = s.split(":");
44987 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44990 // what ever is left... we allow.
44993 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44994 if (!nstyle.length) {
44995 node.removeAttribute('style');
44998 this.iterateChildren(node, this.cleanWord);
45004 * iterateChildren of a Node, calling fn each time, using this as the scole..
45005 * @param {DomNode} node node to iterate children of.
45006 * @param {Function} fn method of this class to call on each item.
45008 iterateChildren : function(node, fn)
45010 if (!node.childNodes.length) {
45013 for (var i = node.childNodes.length-1; i > -1 ; i--) {
45014 fn.call(this, node.childNodes[i])
45020 * cleanTableWidths.
45022 * Quite often pasting from word etc.. results in tables with column and widths.
45023 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
45026 cleanTableWidths : function(node)
45031 this.cleanTableWidths(this.doc.body);
45036 if (node.nodeName == "#text" || node.nodeName == "#comment") {
45039 Roo.log(node.tagName);
45040 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
45041 this.iterateChildren(node, this.cleanTableWidths);
45044 if (node.hasAttribute('width')) {
45045 node.removeAttribute('width');
45049 if (node.hasAttribute("style")) {
45052 var styles = node.getAttribute("style").split(";");
45054 Roo.each(styles, function(s) {
45055 if (!s.match(/:/)) {
45058 var kv = s.split(":");
45059 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
45062 // what ever is left... we allow.
45065 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
45066 if (!nstyle.length) {
45067 node.removeAttribute('style');
45071 this.iterateChildren(node, this.cleanTableWidths);
45079 domToHTML : function(currentElement, depth, nopadtext) {
45081 depth = depth || 0;
45082 nopadtext = nopadtext || false;
45084 if (!currentElement) {
45085 return this.domToHTML(this.doc.body);
45088 //Roo.log(currentElement);
45090 var allText = false;
45091 var nodeName = currentElement.nodeName;
45092 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
45094 if (nodeName == '#text') {
45096 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
45101 if (nodeName != 'BODY') {
45104 // Prints the node tagName, such as <A>, <IMG>, etc
45107 for(i = 0; i < currentElement.attributes.length;i++) {
45109 var aname = currentElement.attributes.item(i).name;
45110 if (!currentElement.attributes.item(i).value.length) {
45113 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
45116 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
45125 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
45128 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
45133 // Traverse the tree
45135 var currentElementChild = currentElement.childNodes.item(i);
45136 var allText = true;
45137 var innerHTML = '';
45139 while (currentElementChild) {
45140 // Formatting code (indent the tree so it looks nice on the screen)
45141 var nopad = nopadtext;
45142 if (lastnode == 'SPAN') {
45146 if (currentElementChild.nodeName == '#text') {
45147 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
45148 toadd = nopadtext ? toadd : toadd.trim();
45149 if (!nopad && toadd.length > 80) {
45150 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
45152 innerHTML += toadd;
45155 currentElementChild = currentElement.childNodes.item(i);
45161 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
45163 // Recursively traverse the tree structure of the child node
45164 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
45165 lastnode = currentElementChild.nodeName;
45167 currentElementChild=currentElement.childNodes.item(i);
45173 // The remaining code is mostly for formatting the tree
45174 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
45179 ret+= "</"+tagName+">";
45185 applyBlacklists : function()
45187 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
45188 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
45192 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
45193 if (b.indexOf(tag) > -1) {
45196 this.white.push(tag);
45200 Roo.each(w, function(tag) {
45201 if (b.indexOf(tag) > -1) {
45204 if (this.white.indexOf(tag) > -1) {
45207 this.white.push(tag);
45212 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
45213 if (w.indexOf(tag) > -1) {
45216 this.black.push(tag);
45220 Roo.each(b, function(tag) {
45221 if (w.indexOf(tag) > -1) {
45224 if (this.black.indexOf(tag) > -1) {
45227 this.black.push(tag);
45232 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45233 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45237 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45238 if (b.indexOf(tag) > -1) {
45241 this.cwhite.push(tag);
45245 Roo.each(w, function(tag) {
45246 if (b.indexOf(tag) > -1) {
45249 if (this.cwhite.indexOf(tag) > -1) {
45252 this.cwhite.push(tag);
45257 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45258 if (w.indexOf(tag) > -1) {
45261 this.cblack.push(tag);
45265 Roo.each(b, function(tag) {
45266 if (w.indexOf(tag) > -1) {
45269 if (this.cblack.indexOf(tag) > -1) {
45272 this.cblack.push(tag);
45277 setStylesheets : function(stylesheets)
45279 if(typeof(stylesheets) == 'string'){
45280 Roo.get(this.iframe.contentDocument.head).createChild({
45282 rel : 'stylesheet',
45291 Roo.each(stylesheets, function(s) {
45296 Roo.get(_this.iframe.contentDocument.head).createChild({
45298 rel : 'stylesheet',
45307 removeStylesheets : function()
45311 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45316 setStyle : function(style)
45318 Roo.get(this.iframe.contentDocument.head).createChild({
45327 // hide stuff that is not compatible
45341 * @event specialkey
45345 * @cfg {String} fieldClass @hide
45348 * @cfg {String} focusClass @hide
45351 * @cfg {String} autoCreate @hide
45354 * @cfg {String} inputType @hide
45357 * @cfg {String} invalidClass @hide
45360 * @cfg {String} invalidText @hide
45363 * @cfg {String} msgFx @hide
45366 * @cfg {String} validateOnBlur @hide
45370 Roo.HtmlEditorCore.white = [
45371 'area', 'br', 'img', 'input', 'hr', 'wbr',
45373 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45374 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45375 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45376 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45377 'table', 'ul', 'xmp',
45379 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45382 'dir', 'menu', 'ol', 'ul', 'dl',
45388 Roo.HtmlEditorCore.black = [
45389 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45391 'base', 'basefont', 'bgsound', 'blink', 'body',
45392 'frame', 'frameset', 'head', 'html', 'ilayer',
45393 'iframe', 'layer', 'link', 'meta', 'object',
45394 'script', 'style' ,'title', 'xml' // clean later..
45396 Roo.HtmlEditorCore.clean = [
45397 'script', 'style', 'title', 'xml'
45399 Roo.HtmlEditorCore.remove = [
45404 Roo.HtmlEditorCore.ablack = [
45408 Roo.HtmlEditorCore.aclean = [
45409 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45413 Roo.HtmlEditorCore.pwhite= [
45414 'http', 'https', 'mailto'
45417 // white listed style attributes.
45418 Roo.HtmlEditorCore.cwhite= [
45419 // 'text-align', /// default is to allow most things..
45425 // black listed style attributes.
45426 Roo.HtmlEditorCore.cblack= [
45427 // 'font-size' -- this can be set by the project
45431 Roo.HtmlEditorCore.swapCodes =[
45432 [ 8211, "–" ],
45433 [ 8212, "—" ],
45442 //<script type="text/javascript">
45445 * Ext JS Library 1.1.1
45446 * Copyright(c) 2006-2007, Ext JS, LLC.
45452 Roo.form.HtmlEditor = function(config){
45456 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45458 if (!this.toolbars) {
45459 this.toolbars = [];
45461 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45467 * @class Roo.form.HtmlEditor
45468 * @extends Roo.form.Field
45469 * Provides a lightweight HTML Editor component.
45471 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45473 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45474 * supported by this editor.</b><br/><br/>
45475 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45476 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45478 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45480 * @cfg {Boolean} clearUp
45484 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45489 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45494 * @cfg {Number} height (in pixels)
45498 * @cfg {Number} width (in pixels)
45503 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45506 stylesheets: false,
45510 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45515 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45521 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45526 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45531 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
45533 allowComments: false,
45538 // private properties
45539 validationEvent : false,
45541 initialized : false,
45544 onFocus : Roo.emptyFn,
45546 hideMode:'offsets',
45548 actionMode : 'container', // defaults to hiding it...
45550 defaultAutoCreate : { // modified by initCompnoent..
45552 style:"width:500px;height:300px;",
45553 autocomplete: "new-password"
45557 initComponent : function(){
45560 * @event initialize
45561 * Fires when the editor is fully initialized (including the iframe)
45562 * @param {HtmlEditor} this
45567 * Fires when the editor is first receives the focus. Any insertion must wait
45568 * until after this event.
45569 * @param {HtmlEditor} this
45573 * @event beforesync
45574 * Fires before the textarea is updated with content from the editor iframe. Return false
45575 * to cancel the sync.
45576 * @param {HtmlEditor} this
45577 * @param {String} html
45581 * @event beforepush
45582 * Fires before the iframe editor is updated with content from the textarea. Return false
45583 * to cancel the push.
45584 * @param {HtmlEditor} this
45585 * @param {String} html
45590 * Fires when the textarea is updated with content from the editor iframe.
45591 * @param {HtmlEditor} this
45592 * @param {String} html
45597 * Fires when the iframe editor is updated with content from the textarea.
45598 * @param {HtmlEditor} this
45599 * @param {String} html
45603 * @event editmodechange
45604 * Fires when the editor switches edit modes
45605 * @param {HtmlEditor} this
45606 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45608 editmodechange: true,
45610 * @event editorevent
45611 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45612 * @param {HtmlEditor} this
45616 * @event firstfocus
45617 * Fires when on first focus - needed by toolbars..
45618 * @param {HtmlEditor} this
45623 * Auto save the htmlEditor value as a file into Events
45624 * @param {HtmlEditor} this
45628 * @event savedpreview
45629 * preview the saved version of htmlEditor
45630 * @param {HtmlEditor} this
45632 savedpreview: true,
45635 * @event stylesheetsclick
45636 * Fires when press the Sytlesheets button
45637 * @param {Roo.HtmlEditorCore} this
45639 stylesheetsclick: true
45641 this.defaultAutoCreate = {
45643 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45644 autocomplete: "new-password"
45649 * Protected method that will not generally be called directly. It
45650 * is called when the editor creates its toolbar. Override this method if you need to
45651 * add custom toolbar buttons.
45652 * @param {HtmlEditor} editor
45654 createToolbar : function(editor){
45655 Roo.log("create toolbars");
45656 if (!editor.toolbars || !editor.toolbars.length) {
45657 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45660 for (var i =0 ; i < editor.toolbars.length;i++) {
45661 editor.toolbars[i] = Roo.factory(
45662 typeof(editor.toolbars[i]) == 'string' ?
45663 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45664 Roo.form.HtmlEditor);
45665 editor.toolbars[i].init(editor);
45673 onRender : function(ct, position)
45676 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45678 this.wrap = this.el.wrap({
45679 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45682 this.editorcore.onRender(ct, position);
45684 if (this.resizable) {
45685 this.resizeEl = new Roo.Resizable(this.wrap, {
45689 minHeight : this.height,
45690 height: this.height,
45691 handles : this.resizable,
45694 resize : function(r, w, h) {
45695 _t.onResize(w,h); // -something
45701 this.createToolbar(this);
45705 this.setSize(this.wrap.getSize());
45707 if (this.resizeEl) {
45708 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45709 // should trigger onReize..
45712 this.keyNav = new Roo.KeyNav(this.el, {
45714 "tab" : function(e){
45715 e.preventDefault();
45717 var value = this.getValue();
45719 var start = this.el.dom.selectionStart;
45720 var end = this.el.dom.selectionEnd;
45724 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45725 this.el.dom.setSelectionRange(end + 1, end + 1);
45729 var f = value.substring(0, start).split("\t");
45731 if(f.pop().length != 0){
45735 this.setValue(f.join("\t") + value.substring(end));
45736 this.el.dom.setSelectionRange(start - 1, start - 1);
45740 "home" : function(e){
45741 e.preventDefault();
45743 var curr = this.el.dom.selectionStart;
45744 var lines = this.getValue().split("\n");
45751 this.el.dom.setSelectionRange(0, 0);
45757 for (var i = 0; i < lines.length;i++) {
45758 pos += lines[i].length;
45768 pos -= lines[i].length;
45774 this.el.dom.setSelectionRange(pos, pos);
45778 this.el.dom.selectionStart = pos;
45779 this.el.dom.selectionEnd = curr;
45782 "end" : function(e){
45783 e.preventDefault();
45785 var curr = this.el.dom.selectionStart;
45786 var lines = this.getValue().split("\n");
45793 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45799 for (var i = 0; i < lines.length;i++) {
45801 pos += lines[i].length;
45815 this.el.dom.setSelectionRange(pos, pos);
45819 this.el.dom.selectionStart = curr;
45820 this.el.dom.selectionEnd = pos;
45825 doRelay : function(foo, bar, hname){
45826 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45832 // if(this.autosave && this.w){
45833 // this.autoSaveFn = setInterval(this.autosave, 1000);
45838 onResize : function(w, h)
45840 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45845 if(typeof w == 'number'){
45846 var aw = w - this.wrap.getFrameWidth('lr');
45847 this.el.setWidth(this.adjustWidth('textarea', aw));
45850 if(typeof h == 'number'){
45852 for (var i =0; i < this.toolbars.length;i++) {
45853 // fixme - ask toolbars for heights?
45854 tbh += this.toolbars[i].tb.el.getHeight();
45855 if (this.toolbars[i].footer) {
45856 tbh += this.toolbars[i].footer.el.getHeight();
45863 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45864 ah -= 5; // knock a few pixes off for look..
45866 this.el.setHeight(this.adjustWidth('textarea', ah));
45870 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45871 this.editorcore.onResize(ew,eh);
45876 * Toggles the editor between standard and source edit mode.
45877 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45879 toggleSourceEdit : function(sourceEditMode)
45881 this.editorcore.toggleSourceEdit(sourceEditMode);
45883 if(this.editorcore.sourceEditMode){
45884 Roo.log('editor - showing textarea');
45887 // Roo.log(this.syncValue());
45888 this.editorcore.syncValue();
45889 this.el.removeClass('x-hidden');
45890 this.el.dom.removeAttribute('tabIndex');
45893 for (var i = 0; i < this.toolbars.length; i++) {
45894 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45895 this.toolbars[i].tb.hide();
45896 this.toolbars[i].footer.hide();
45901 Roo.log('editor - hiding textarea');
45903 // Roo.log(this.pushValue());
45904 this.editorcore.pushValue();
45906 this.el.addClass('x-hidden');
45907 this.el.dom.setAttribute('tabIndex', -1);
45909 for (var i = 0; i < this.toolbars.length; i++) {
45910 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45911 this.toolbars[i].tb.show();
45912 this.toolbars[i].footer.show();
45916 //this.deferFocus();
45919 this.setSize(this.wrap.getSize());
45920 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45922 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45925 // private (for BoxComponent)
45926 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45928 // private (for BoxComponent)
45929 getResizeEl : function(){
45933 // private (for BoxComponent)
45934 getPositionEl : function(){
45939 initEvents : function(){
45940 this.originalValue = this.getValue();
45944 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45947 markInvalid : Roo.emptyFn,
45949 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45952 clearInvalid : Roo.emptyFn,
45954 setValue : function(v){
45955 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45956 this.editorcore.pushValue();
45961 deferFocus : function(){
45962 this.focus.defer(10, this);
45966 focus : function(){
45967 this.editorcore.focus();
45973 onDestroy : function(){
45979 for (var i =0; i < this.toolbars.length;i++) {
45980 // fixme - ask toolbars for heights?
45981 this.toolbars[i].onDestroy();
45984 this.wrap.dom.innerHTML = '';
45985 this.wrap.remove();
45990 onFirstFocus : function(){
45991 //Roo.log("onFirstFocus");
45992 this.editorcore.onFirstFocus();
45993 for (var i =0; i < this.toolbars.length;i++) {
45994 this.toolbars[i].onFirstFocus();
46000 syncValue : function()
46002 this.editorcore.syncValue();
46005 pushValue : function()
46007 this.editorcore.pushValue();
46010 setStylesheets : function(stylesheets)
46012 this.editorcore.setStylesheets(stylesheets);
46015 removeStylesheets : function()
46017 this.editorcore.removeStylesheets();
46021 // hide stuff that is not compatible
46035 * @event specialkey
46039 * @cfg {String} fieldClass @hide
46042 * @cfg {String} focusClass @hide
46045 * @cfg {String} autoCreate @hide
46048 * @cfg {String} inputType @hide
46051 * @cfg {String} invalidClass @hide
46054 * @cfg {String} invalidText @hide
46057 * @cfg {String} msgFx @hide
46060 * @cfg {String} validateOnBlur @hide
46064 // <script type="text/javascript">
46067 * Ext JS Library 1.1.1
46068 * Copyright(c) 2006-2007, Ext JS, LLC.
46074 * @class Roo.form.HtmlEditorToolbar1
46079 new Roo.form.HtmlEditor({
46082 new Roo.form.HtmlEditorToolbar1({
46083 disable : { fonts: 1 , format: 1, ..., ... , ...],
46089 * @cfg {Object} disable List of elements to disable..
46090 * @cfg {Array} btns List of additional buttons.
46094 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
46097 Roo.form.HtmlEditor.ToolbarStandard = function(config)
46100 Roo.apply(this, config);
46102 // default disabled, based on 'good practice'..
46103 this.disable = this.disable || {};
46104 Roo.applyIf(this.disable, {
46107 specialElements : true
46111 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46112 // dont call parent... till later.
46115 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
46122 editorcore : false,
46124 * @cfg {Object} disable List of toolbar elements to disable
46131 * @cfg {String} createLinkText The default text for the create link prompt
46133 createLinkText : 'Please enter the URL for the link:',
46135 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
46137 defaultLinkValue : 'http:/'+'/',
46141 * @cfg {Array} fontFamilies An array of available font families
46159 // "á" , ?? a acute?
46164 "°" // , // degrees
46166 // "é" , // e ecute
46167 // "ú" , // u ecute?
46170 specialElements : [
46172 text: "Insert Table",
46175 ihtml : '<table><tr><td>Cell</td></tr></table>'
46179 text: "Insert Image",
46182 ihtml : '<img src="about:blank"/>'
46191 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
46192 "input:submit", "input:button", "select", "textarea", "label" ],
46195 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
46197 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
46206 * @cfg {String} defaultFont default font to use.
46208 defaultFont: 'tahoma',
46210 fontSelect : false,
46213 formatCombo : false,
46215 init : function(editor)
46217 this.editor = editor;
46218 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46219 var editorcore = this.editorcore;
46223 var fid = editorcore.frameId;
46225 function btn(id, toggle, handler){
46226 var xid = fid + '-'+ id ;
46230 cls : 'x-btn-icon x-edit-'+id,
46231 enableToggle:toggle !== false,
46232 scope: _t, // was editor...
46233 handler:handler||_t.relayBtnCmd,
46234 clickEvent:'mousedown',
46235 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46242 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46244 // stop form submits
46245 tb.el.on('click', function(e){
46246 e.preventDefault(); // what does this do?
46249 if(!this.disable.font) { // && !Roo.isSafari){
46250 /* why no safari for fonts
46251 editor.fontSelect = tb.el.createChild({
46254 cls:'x-font-select',
46255 html: this.createFontOptions()
46258 editor.fontSelect.on('change', function(){
46259 var font = editor.fontSelect.dom.value;
46260 editor.relayCmd('fontname', font);
46261 editor.deferFocus();
46265 editor.fontSelect.dom,
46271 if(!this.disable.formats){
46272 this.formatCombo = new Roo.form.ComboBox({
46273 store: new Roo.data.SimpleStore({
46276 data : this.formats // from states.js
46280 //autoCreate : {tag: "div", size: "20"},
46281 displayField:'tag',
46285 triggerAction: 'all',
46286 emptyText:'Add tag',
46287 selectOnFocus:true,
46290 'select': function(c, r, i) {
46291 editorcore.insertTag(r.get('tag'));
46297 tb.addField(this.formatCombo);
46301 if(!this.disable.format){
46306 btn('strikethrough')
46309 if(!this.disable.fontSize){
46314 btn('increasefontsize', false, editorcore.adjustFont),
46315 btn('decreasefontsize', false, editorcore.adjustFont)
46320 if(!this.disable.colors){
46323 id:editorcore.frameId +'-forecolor',
46324 cls:'x-btn-icon x-edit-forecolor',
46325 clickEvent:'mousedown',
46326 tooltip: this.buttonTips['forecolor'] || undefined,
46328 menu : new Roo.menu.ColorMenu({
46329 allowReselect: true,
46330 focus: Roo.emptyFn,
46333 selectHandler: function(cp, color){
46334 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46335 editor.deferFocus();
46338 clickEvent:'mousedown'
46341 id:editorcore.frameId +'backcolor',
46342 cls:'x-btn-icon x-edit-backcolor',
46343 clickEvent:'mousedown',
46344 tooltip: this.buttonTips['backcolor'] || undefined,
46346 menu : new Roo.menu.ColorMenu({
46347 focus: Roo.emptyFn,
46350 allowReselect: true,
46351 selectHandler: function(cp, color){
46353 editorcore.execCmd('useCSS', false);
46354 editorcore.execCmd('hilitecolor', color);
46355 editorcore.execCmd('useCSS', true);
46356 editor.deferFocus();
46358 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46359 Roo.isSafari || Roo.isIE ? '#'+color : color);
46360 editor.deferFocus();
46364 clickEvent:'mousedown'
46369 // now add all the items...
46372 if(!this.disable.alignments){
46375 btn('justifyleft'),
46376 btn('justifycenter'),
46377 btn('justifyright')
46381 //if(!Roo.isSafari){
46382 if(!this.disable.links){
46385 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46389 if(!this.disable.lists){
46392 btn('insertorderedlist'),
46393 btn('insertunorderedlist')
46396 if(!this.disable.sourceEdit){
46399 btn('sourceedit', true, function(btn){
46400 this.toggleSourceEdit(btn.pressed);
46407 // special menu.. - needs to be tidied up..
46408 if (!this.disable.special) {
46411 cls: 'x-edit-none',
46417 for (var i =0; i < this.specialChars.length; i++) {
46418 smenu.menu.items.push({
46420 html: this.specialChars[i],
46421 handler: function(a,b) {
46422 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46423 //editor.insertAtCursor(a.html);
46437 if (!this.disable.cleanStyles) {
46439 cls: 'x-btn-icon x-btn-clear',
46445 for (var i =0; i < this.cleanStyles.length; i++) {
46446 cmenu.menu.items.push({
46447 actiontype : this.cleanStyles[i],
46448 html: 'Remove ' + this.cleanStyles[i],
46449 handler: function(a,b) {
46452 var c = Roo.get(editorcore.doc.body);
46453 c.select('[style]').each(function(s) {
46454 s.dom.style.removeProperty(a.actiontype);
46456 editorcore.syncValue();
46461 cmenu.menu.items.push({
46462 actiontype : 'tablewidths',
46463 html: 'Remove Table Widths',
46464 handler: function(a,b) {
46465 editorcore.cleanTableWidths();
46466 editorcore.syncValue();
46470 cmenu.menu.items.push({
46471 actiontype : 'word',
46472 html: 'Remove MS Word Formating',
46473 handler: function(a,b) {
46474 editorcore.cleanWord();
46475 editorcore.syncValue();
46480 cmenu.menu.items.push({
46481 actiontype : 'all',
46482 html: 'Remove All Styles',
46483 handler: function(a,b) {
46485 var c = Roo.get(editorcore.doc.body);
46486 c.select('[style]').each(function(s) {
46487 s.dom.removeAttribute('style');
46489 editorcore.syncValue();
46494 cmenu.menu.items.push({
46495 actiontype : 'all',
46496 html: 'Remove All CSS Classes',
46497 handler: function(a,b) {
46499 var c = Roo.get(editorcore.doc.body);
46500 c.select('[class]').each(function(s) {
46501 s.dom.removeAttribute('class');
46503 editorcore.cleanWord();
46504 editorcore.syncValue();
46509 cmenu.menu.items.push({
46510 actiontype : 'tidy',
46511 html: 'Tidy HTML Source',
46512 handler: function(a,b) {
46513 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46514 editorcore.syncValue();
46523 if (!this.disable.specialElements) {
46526 cls: 'x-edit-none',
46531 for (var i =0; i < this.specialElements.length; i++) {
46532 semenu.menu.items.push(
46534 handler: function(a,b) {
46535 editor.insertAtCursor(this.ihtml);
46537 }, this.specialElements[i])
46549 for(var i =0; i< this.btns.length;i++) {
46550 var b = Roo.factory(this.btns[i],Roo.form);
46551 b.cls = 'x-edit-none';
46553 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46554 b.cls += ' x-init-enable';
46557 b.scope = editorcore;
46565 // disable everything...
46567 this.tb.items.each(function(item){
46570 item.id != editorcore.frameId+ '-sourceedit' &&
46571 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46577 this.rendered = true;
46579 // the all the btns;
46580 editor.on('editorevent', this.updateToolbar, this);
46581 // other toolbars need to implement this..
46582 //editor.on('editmodechange', this.updateToolbar, this);
46586 relayBtnCmd : function(btn) {
46587 this.editorcore.relayCmd(btn.cmd);
46589 // private used internally
46590 createLink : function(){
46591 Roo.log("create link?");
46592 var url = prompt(this.createLinkText, this.defaultLinkValue);
46593 if(url && url != 'http:/'+'/'){
46594 this.editorcore.relayCmd('createlink', url);
46600 * Protected method that will not generally be called directly. It triggers
46601 * a toolbar update by reading the markup state of the current selection in the editor.
46603 updateToolbar: function(){
46605 if(!this.editorcore.activated){
46606 this.editor.onFirstFocus();
46610 var btns = this.tb.items.map,
46611 doc = this.editorcore.doc,
46612 frameId = this.editorcore.frameId;
46614 if(!this.disable.font && !Roo.isSafari){
46616 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46617 if(name != this.fontSelect.dom.value){
46618 this.fontSelect.dom.value = name;
46622 if(!this.disable.format){
46623 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46624 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46625 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46626 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46628 if(!this.disable.alignments){
46629 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46630 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46631 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46633 if(!Roo.isSafari && !this.disable.lists){
46634 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46635 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46638 var ans = this.editorcore.getAllAncestors();
46639 if (this.formatCombo) {
46642 var store = this.formatCombo.store;
46643 this.formatCombo.setValue("");
46644 for (var i =0; i < ans.length;i++) {
46645 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46647 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46655 // hides menus... - so this cant be on a menu...
46656 Roo.menu.MenuMgr.hideAll();
46658 //this.editorsyncValue();
46662 createFontOptions : function(){
46663 var buf = [], fs = this.fontFamilies, ff, lc;
46667 for(var i = 0, len = fs.length; i< len; i++){
46669 lc = ff.toLowerCase();
46671 '<option value="',lc,'" style="font-family:',ff,';"',
46672 (this.defaultFont == lc ? ' selected="true">' : '>'),
46677 return buf.join('');
46680 toggleSourceEdit : function(sourceEditMode){
46682 Roo.log("toolbar toogle");
46683 if(sourceEditMode === undefined){
46684 sourceEditMode = !this.sourceEditMode;
46686 this.sourceEditMode = sourceEditMode === true;
46687 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46688 // just toggle the button?
46689 if(btn.pressed !== this.sourceEditMode){
46690 btn.toggle(this.sourceEditMode);
46694 if(sourceEditMode){
46695 Roo.log("disabling buttons");
46696 this.tb.items.each(function(item){
46697 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46703 Roo.log("enabling buttons");
46704 if(this.editorcore.initialized){
46705 this.tb.items.each(function(item){
46711 Roo.log("calling toggole on editor");
46712 // tell the editor that it's been pressed..
46713 this.editor.toggleSourceEdit(sourceEditMode);
46717 * Object collection of toolbar tooltips for the buttons in the editor. The key
46718 * is the command id associated with that button and the value is a valid QuickTips object.
46723 title: 'Bold (Ctrl+B)',
46724 text: 'Make the selected text bold.',
46725 cls: 'x-html-editor-tip'
46728 title: 'Italic (Ctrl+I)',
46729 text: 'Make the selected text italic.',
46730 cls: 'x-html-editor-tip'
46738 title: 'Bold (Ctrl+B)',
46739 text: 'Make the selected text bold.',
46740 cls: 'x-html-editor-tip'
46743 title: 'Italic (Ctrl+I)',
46744 text: 'Make the selected text italic.',
46745 cls: 'x-html-editor-tip'
46748 title: 'Underline (Ctrl+U)',
46749 text: 'Underline the selected text.',
46750 cls: 'x-html-editor-tip'
46753 title: 'Strikethrough',
46754 text: 'Strikethrough the selected text.',
46755 cls: 'x-html-editor-tip'
46757 increasefontsize : {
46758 title: 'Grow Text',
46759 text: 'Increase the font size.',
46760 cls: 'x-html-editor-tip'
46762 decreasefontsize : {
46763 title: 'Shrink Text',
46764 text: 'Decrease the font size.',
46765 cls: 'x-html-editor-tip'
46768 title: 'Text Highlight Color',
46769 text: 'Change the background color of the selected text.',
46770 cls: 'x-html-editor-tip'
46773 title: 'Font Color',
46774 text: 'Change the color of the selected text.',
46775 cls: 'x-html-editor-tip'
46778 title: 'Align Text Left',
46779 text: 'Align text to the left.',
46780 cls: 'x-html-editor-tip'
46783 title: 'Center Text',
46784 text: 'Center text in the editor.',
46785 cls: 'x-html-editor-tip'
46788 title: 'Align Text Right',
46789 text: 'Align text to the right.',
46790 cls: 'x-html-editor-tip'
46792 insertunorderedlist : {
46793 title: 'Bullet List',
46794 text: 'Start a bulleted list.',
46795 cls: 'x-html-editor-tip'
46797 insertorderedlist : {
46798 title: 'Numbered List',
46799 text: 'Start a numbered list.',
46800 cls: 'x-html-editor-tip'
46803 title: 'Hyperlink',
46804 text: 'Make the selected text a hyperlink.',
46805 cls: 'x-html-editor-tip'
46808 title: 'Source Edit',
46809 text: 'Switch to source editing mode.',
46810 cls: 'x-html-editor-tip'
46814 onDestroy : function(){
46817 this.tb.items.each(function(item){
46819 item.menu.removeAll();
46821 item.menu.el.destroy();
46829 onFirstFocus: function() {
46830 this.tb.items.each(function(item){
46839 // <script type="text/javascript">
46842 * Ext JS Library 1.1.1
46843 * Copyright(c) 2006-2007, Ext JS, LLC.
46850 * @class Roo.form.HtmlEditor.ToolbarContext
46855 new Roo.form.HtmlEditor({
46858 { xtype: 'ToolbarStandard', styles : {} }
46859 { xtype: 'ToolbarContext', disable : {} }
46865 * @config : {Object} disable List of elements to disable.. (not done yet.)
46866 * @config : {Object} styles Map of styles available.
46870 Roo.form.HtmlEditor.ToolbarContext = function(config)
46873 Roo.apply(this, config);
46874 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46875 // dont call parent... till later.
46876 this.styles = this.styles || {};
46881 Roo.form.HtmlEditor.ToolbarContext.types = {
46893 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46959 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46964 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46974 style : 'fontFamily',
46975 displayField: 'display',
46976 optname : 'font-family',
47025 // should we really allow this??
47026 // should this just be
47037 style : 'fontFamily',
47038 displayField: 'display',
47039 optname : 'font-family',
47046 style : 'fontFamily',
47047 displayField: 'display',
47048 optname : 'font-family',
47055 style : 'fontFamily',
47056 displayField: 'display',
47057 optname : 'font-family',
47068 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
47069 Roo.form.HtmlEditor.ToolbarContext.stores = false;
47071 Roo.form.HtmlEditor.ToolbarContext.options = {
47073 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
47074 [ 'Courier New', 'Courier New'],
47075 [ 'Tahoma', 'Tahoma'],
47076 [ 'Times New Roman,serif', 'Times'],
47077 [ 'Verdana','Verdana' ]
47081 // fixme - these need to be configurable..
47084 //Roo.form.HtmlEditor.ToolbarContext.types
47087 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
47094 editorcore : false,
47096 * @cfg {Object} disable List of toolbar elements to disable
47101 * @cfg {Object} styles List of styles
47102 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
47104 * These must be defined in the page, so they get rendered correctly..
47115 init : function(editor)
47117 this.editor = editor;
47118 this.editorcore = editor.editorcore ? editor.editorcore : editor;
47119 var editorcore = this.editorcore;
47121 var fid = editorcore.frameId;
47123 function btn(id, toggle, handler){
47124 var xid = fid + '-'+ id ;
47128 cls : 'x-btn-icon x-edit-'+id,
47129 enableToggle:toggle !== false,
47130 scope: editorcore, // was editor...
47131 handler:handler||editorcore.relayBtnCmd,
47132 clickEvent:'mousedown',
47133 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47137 // create a new element.
47138 var wdiv = editor.wrap.createChild({
47140 }, editor.wrap.dom.firstChild.nextSibling, true);
47142 // can we do this more than once??
47144 // stop form submits
47147 // disable everything...
47148 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47149 this.toolbars = {};
47151 for (var i in ty) {
47153 this.toolbars[i] = this.buildToolbar(ty[i],i);
47155 this.tb = this.toolbars.BODY;
47157 this.buildFooter();
47158 this.footer.show();
47159 editor.on('hide', function( ) { this.footer.hide() }, this);
47160 editor.on('show', function( ) { this.footer.show() }, this);
47163 this.rendered = true;
47165 // the all the btns;
47166 editor.on('editorevent', this.updateToolbar, this);
47167 // other toolbars need to implement this..
47168 //editor.on('editmodechange', this.updateToolbar, this);
47174 * Protected method that will not generally be called directly. It triggers
47175 * a toolbar update by reading the markup state of the current selection in the editor.
47177 * Note you can force an update by calling on('editorevent', scope, false)
47179 updateToolbar: function(editor,ev,sel){
47182 // capture mouse up - this is handy for selecting images..
47183 // perhaps should go somewhere else...
47184 if(!this.editorcore.activated){
47185 this.editor.onFirstFocus();
47191 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
47192 // selectNode - might want to handle IE?
47194 (ev.type == 'mouseup' || ev.type == 'click' ) &&
47195 ev.target && ev.target.tagName == 'IMG') {
47196 // they have click on an image...
47197 // let's see if we can change the selection...
47200 var nodeRange = sel.ownerDocument.createRange();
47202 nodeRange.selectNode(sel);
47204 nodeRange.selectNodeContents(sel);
47206 //nodeRange.collapse(true);
47207 var s = this.editorcore.win.getSelection();
47208 s.removeAllRanges();
47209 s.addRange(nodeRange);
47213 var updateFooter = sel ? false : true;
47216 var ans = this.editorcore.getAllAncestors();
47219 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47222 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47223 sel = sel ? sel : this.editorcore.doc.body;
47224 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47227 // pick a menu that exists..
47228 var tn = sel.tagName.toUpperCase();
47229 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47231 tn = sel.tagName.toUpperCase();
47233 var lastSel = this.tb.selectedNode;
47235 this.tb.selectedNode = sel;
47237 // if current menu does not match..
47239 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47242 ///console.log("show: " + tn);
47243 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47246 this.tb.items.first().el.innerHTML = tn + ': ';
47249 // update attributes
47250 if (this.tb.fields) {
47251 this.tb.fields.each(function(e) {
47253 e.setValue(sel.style[e.stylename]);
47256 e.setValue(sel.getAttribute(e.attrname));
47260 var hasStyles = false;
47261 for(var i in this.styles) {
47268 var st = this.tb.fields.item(0);
47270 st.store.removeAll();
47273 var cn = sel.className.split(/\s+/);
47276 if (this.styles['*']) {
47278 Roo.each(this.styles['*'], function(v) {
47279 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47282 if (this.styles[tn]) {
47283 Roo.each(this.styles[tn], function(v) {
47284 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47288 st.store.loadData(avs);
47292 // flag our selected Node.
47293 this.tb.selectedNode = sel;
47296 Roo.menu.MenuMgr.hideAll();
47300 if (!updateFooter) {
47301 //this.footDisp.dom.innerHTML = '';
47304 // update the footer
47308 this.footerEls = ans.reverse();
47309 Roo.each(this.footerEls, function(a,i) {
47310 if (!a) { return; }
47311 html += html.length ? ' > ' : '';
47313 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47318 var sz = this.footDisp.up('td').getSize();
47319 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47320 this.footDisp.dom.style.marginLeft = '5px';
47322 this.footDisp.dom.style.overflow = 'hidden';
47324 this.footDisp.dom.innerHTML = html;
47326 //this.editorsyncValue();
47333 onDestroy : function(){
47336 this.tb.items.each(function(item){
47338 item.menu.removeAll();
47340 item.menu.el.destroy();
47348 onFirstFocus: function() {
47349 // need to do this for all the toolbars..
47350 this.tb.items.each(function(item){
47354 buildToolbar: function(tlist, nm)
47356 var editor = this.editor;
47357 var editorcore = this.editorcore;
47358 // create a new element.
47359 var wdiv = editor.wrap.createChild({
47361 }, editor.wrap.dom.firstChild.nextSibling, true);
47364 var tb = new Roo.Toolbar(wdiv);
47367 tb.add(nm+ ": ");
47370 for(var i in this.styles) {
47375 if (styles && styles.length) {
47377 // this needs a multi-select checkbox...
47378 tb.addField( new Roo.form.ComboBox({
47379 store: new Roo.data.SimpleStore({
47381 fields: ['val', 'selected'],
47384 name : '-roo-edit-className',
47385 attrname : 'className',
47386 displayField: 'val',
47390 triggerAction: 'all',
47391 emptyText:'Select Style',
47392 selectOnFocus:true,
47395 'select': function(c, r, i) {
47396 // initial support only for on class per el..
47397 tb.selectedNode.className = r ? r.get('val') : '';
47398 editorcore.syncValue();
47405 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47406 var tbops = tbc.options;
47408 for (var i in tlist) {
47410 var item = tlist[i];
47411 tb.add(item.title + ": ");
47414 //optname == used so you can configure the options available..
47415 var opts = item.opts ? item.opts : false;
47416 if (item.optname) {
47417 opts = tbops[item.optname];
47422 // opts == pulldown..
47423 tb.addField( new Roo.form.ComboBox({
47424 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47426 fields: ['val', 'display'],
47429 name : '-roo-edit-' + i,
47431 stylename : item.style ? item.style : false,
47432 displayField: item.displayField ? item.displayField : 'val',
47433 valueField : 'val',
47435 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47437 triggerAction: 'all',
47438 emptyText:'Select',
47439 selectOnFocus:true,
47440 width: item.width ? item.width : 130,
47442 'select': function(c, r, i) {
47444 tb.selectedNode.style[c.stylename] = r.get('val');
47447 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47456 tb.addField( new Roo.form.TextField({
47459 //allowBlank:false,
47464 tb.addField( new Roo.form.TextField({
47465 name: '-roo-edit-' + i,
47472 'change' : function(f, nv, ov) {
47473 tb.selectedNode.setAttribute(f.attrname, nv);
47474 editorcore.syncValue();
47487 text: 'Stylesheets',
47490 click : function ()
47492 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47500 text: 'Remove Tag',
47503 click : function ()
47506 // undo does not work.
47508 var sn = tb.selectedNode;
47510 var pn = sn.parentNode;
47512 var stn = sn.childNodes[0];
47513 var en = sn.childNodes[sn.childNodes.length - 1 ];
47514 while (sn.childNodes.length) {
47515 var node = sn.childNodes[0];
47516 sn.removeChild(node);
47518 pn.insertBefore(node, sn);
47521 pn.removeChild(sn);
47522 var range = editorcore.createRange();
47524 range.setStart(stn,0);
47525 range.setEnd(en,0); //????
47526 //range.selectNode(sel);
47529 var selection = editorcore.getSelection();
47530 selection.removeAllRanges();
47531 selection.addRange(range);
47535 //_this.updateToolbar(null, null, pn);
47536 _this.updateToolbar(null, null, null);
47537 _this.footDisp.dom.innerHTML = '';
47547 tb.el.on('click', function(e){
47548 e.preventDefault(); // what does this do?
47550 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47553 // dont need to disable them... as they will get hidden
47558 buildFooter : function()
47561 var fel = this.editor.wrap.createChild();
47562 this.footer = new Roo.Toolbar(fel);
47563 // toolbar has scrolly on left / right?
47564 var footDisp= new Roo.Toolbar.Fill();
47570 handler : function() {
47571 _t.footDisp.scrollTo('left',0,true)
47575 this.footer.add( footDisp );
47580 handler : function() {
47582 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47586 var fel = Roo.get(footDisp.el);
47587 fel.addClass('x-editor-context');
47588 this.footDispWrap = fel;
47589 this.footDispWrap.overflow = 'hidden';
47591 this.footDisp = fel.createChild();
47592 this.footDispWrap.on('click', this.onContextClick, this)
47596 onContextClick : function (ev,dom)
47598 ev.preventDefault();
47599 var cn = dom.className;
47601 if (!cn.match(/x-ed-loc-/)) {
47604 var n = cn.split('-').pop();
47605 var ans = this.footerEls;
47609 var range = this.editorcore.createRange();
47611 range.selectNodeContents(sel);
47612 //range.selectNode(sel);
47615 var selection = this.editorcore.getSelection();
47616 selection.removeAllRanges();
47617 selection.addRange(range);
47621 this.updateToolbar(null, null, sel);
47638 * Ext JS Library 1.1.1
47639 * Copyright(c) 2006-2007, Ext JS, LLC.
47641 * Originally Released Under LGPL - original licence link has changed is not relivant.
47644 * <script type="text/javascript">
47648 * @class Roo.form.BasicForm
47649 * @extends Roo.util.Observable
47650 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47652 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47653 * @param {Object} config Configuration options
47655 Roo.form.BasicForm = function(el, config){
47656 this.allItems = [];
47657 this.childForms = [];
47658 Roo.apply(this, config);
47660 * The Roo.form.Field items in this form.
47661 * @type MixedCollection
47665 this.items = new Roo.util.MixedCollection(false, function(o){
47666 return o.id || (o.id = Roo.id());
47670 * @event beforeaction
47671 * Fires before any action is performed. Return false to cancel the action.
47672 * @param {Form} this
47673 * @param {Action} action The action to be performed
47675 beforeaction: true,
47677 * @event actionfailed
47678 * Fires when an action fails.
47679 * @param {Form} this
47680 * @param {Action} action The action that failed
47682 actionfailed : true,
47684 * @event actioncomplete
47685 * Fires when an action is completed.
47686 * @param {Form} this
47687 * @param {Action} action The action that completed
47689 actioncomplete : true
47694 Roo.form.BasicForm.superclass.constructor.call(this);
47696 Roo.form.BasicForm.popover.apply();
47699 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47701 * @cfg {String} method
47702 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47705 * @cfg {DataReader} reader
47706 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47707 * This is optional as there is built-in support for processing JSON.
47710 * @cfg {DataReader} errorReader
47711 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47712 * This is completely optional as there is built-in support for processing JSON.
47715 * @cfg {String} url
47716 * The URL to use for form actions if one isn't supplied in the action options.
47719 * @cfg {Boolean} fileUpload
47720 * Set to true if this form is a file upload.
47724 * @cfg {Object} baseParams
47725 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47730 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47735 activeAction : null,
47738 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47739 * or setValues() data instead of when the form was first created.
47741 trackResetOnLoad : false,
47745 * childForms - used for multi-tab forms
47748 childForms : false,
47751 * allItems - full list of fields.
47757 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47758 * element by passing it or its id or mask the form itself by passing in true.
47761 waitMsgTarget : false,
47766 disableMask : false,
47769 * @cfg {Boolean} errorMask (true|false) default false
47774 * @cfg {Number} maskOffset Default 100
47779 initEl : function(el){
47780 this.el = Roo.get(el);
47781 this.id = this.el.id || Roo.id();
47782 this.el.on('submit', this.onSubmit, this);
47783 this.el.addClass('x-form');
47787 onSubmit : function(e){
47792 * Returns true if client-side validation on the form is successful.
47795 isValid : function(){
47797 var target = false;
47798 this.items.each(function(f){
47805 if(!target && f.el.isVisible(true)){
47810 if(this.errorMask && !valid){
47811 Roo.form.BasicForm.popover.mask(this, target);
47817 * Returns array of invalid form fields.
47821 invalidFields : function()
47824 this.items.each(function(f){
47837 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47840 isDirty : function(){
47842 this.items.each(function(f){
47852 * Returns true if any fields in this form have changed since their original load. (New version)
47856 hasChanged : function()
47859 this.items.each(function(f){
47860 if(f.hasChanged()){
47869 * Resets all hasChanged to 'false' -
47870 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47871 * So hasChanged storage is only to be used for this purpose
47874 resetHasChanged : function()
47876 this.items.each(function(f){
47877 f.resetHasChanged();
47884 * Performs a predefined action (submit or load) or custom actions you define on this form.
47885 * @param {String} actionName The name of the action type
47886 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47887 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47888 * accept other config options):
47890 Property Type Description
47891 ---------------- --------------- ----------------------------------------------------------------------------------
47892 url String The url for the action (defaults to the form's url)
47893 method String The form method to use (defaults to the form's method, or POST if not defined)
47894 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47895 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47896 validate the form on the client (defaults to false)
47898 * @return {BasicForm} this
47900 doAction : function(action, options){
47901 if(typeof action == 'string'){
47902 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47904 if(this.fireEvent('beforeaction', this, action) !== false){
47905 this.beforeAction(action);
47906 action.run.defer(100, action);
47912 * Shortcut to do a submit action.
47913 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47914 * @return {BasicForm} this
47916 submit : function(options){
47917 this.doAction('submit', options);
47922 * Shortcut to do a load action.
47923 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47924 * @return {BasicForm} this
47926 load : function(options){
47927 this.doAction('load', options);
47932 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47933 * @param {Record} record The record to edit
47934 * @return {BasicForm} this
47936 updateRecord : function(record){
47937 record.beginEdit();
47938 var fs = record.fields;
47939 fs.each(function(f){
47940 var field = this.findField(f.name);
47942 record.set(f.name, field.getValue());
47950 * Loads an Roo.data.Record into this form.
47951 * @param {Record} record The record to load
47952 * @return {BasicForm} this
47954 loadRecord : function(record){
47955 this.setValues(record.data);
47960 beforeAction : function(action){
47961 var o = action.options;
47963 if(!this.disableMask) {
47964 if(this.waitMsgTarget === true){
47965 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47966 }else if(this.waitMsgTarget){
47967 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47968 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47970 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47978 afterAction : function(action, success){
47979 this.activeAction = null;
47980 var o = action.options;
47982 if(!this.disableMask) {
47983 if(this.waitMsgTarget === true){
47985 }else if(this.waitMsgTarget){
47986 this.waitMsgTarget.unmask();
47988 Roo.MessageBox.updateProgress(1);
47989 Roo.MessageBox.hide();
47997 Roo.callback(o.success, o.scope, [this, action]);
47998 this.fireEvent('actioncomplete', this, action);
48002 // failure condition..
48003 // we have a scenario where updates need confirming.
48004 // eg. if a locking scenario exists..
48005 // we look for { errors : { needs_confirm : true }} in the response.
48007 (typeof(action.result) != 'undefined') &&
48008 (typeof(action.result.errors) != 'undefined') &&
48009 (typeof(action.result.errors.needs_confirm) != 'undefined')
48012 Roo.MessageBox.confirm(
48013 "Change requires confirmation",
48014 action.result.errorMsg,
48019 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
48029 Roo.callback(o.failure, o.scope, [this, action]);
48030 // show an error message if no failed handler is set..
48031 if (!this.hasListener('actionfailed')) {
48032 Roo.MessageBox.alert("Error",
48033 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
48034 action.result.errorMsg :
48035 "Saving Failed, please check your entries or try again"
48039 this.fireEvent('actionfailed', this, action);
48045 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
48046 * @param {String} id The value to search for
48049 findField : function(id){
48050 var field = this.items.get(id);
48052 this.items.each(function(f){
48053 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
48059 return field || null;
48063 * Add a secondary form to this one,
48064 * Used to provide tabbed forms. One form is primary, with hidden values
48065 * which mirror the elements from the other forms.
48067 * @param {Roo.form.Form} form to add.
48070 addForm : function(form)
48073 if (this.childForms.indexOf(form) > -1) {
48077 this.childForms.push(form);
48079 Roo.each(form.allItems, function (fe) {
48081 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
48082 if (this.findField(n)) { // already added..
48085 var add = new Roo.form.Hidden({
48088 add.render(this.el);
48095 * Mark fields in this form invalid in bulk.
48096 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
48097 * @return {BasicForm} this
48099 markInvalid : function(errors){
48100 if(errors instanceof Array){
48101 for(var i = 0, len = errors.length; i < len; i++){
48102 var fieldError = errors[i];
48103 var f = this.findField(fieldError.id);
48105 f.markInvalid(fieldError.msg);
48111 if(typeof errors[id] != 'function' && (field = this.findField(id))){
48112 field.markInvalid(errors[id]);
48116 Roo.each(this.childForms || [], function (f) {
48117 f.markInvalid(errors);
48124 * Set values for fields in this form in bulk.
48125 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
48126 * @return {BasicForm} this
48128 setValues : function(values){
48129 if(values instanceof Array){ // array of objects
48130 for(var i = 0, len = values.length; i < len; i++){
48132 var f = this.findField(v.id);
48134 f.setValue(v.value);
48135 if(this.trackResetOnLoad){
48136 f.originalValue = f.getValue();
48140 }else{ // object hash
48143 if(typeof values[id] != 'function' && (field = this.findField(id))){
48145 if (field.setFromData &&
48146 field.valueField &&
48147 field.displayField &&
48148 // combos' with local stores can
48149 // be queried via setValue()
48150 // to set their value..
48151 (field.store && !field.store.isLocal)
48155 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
48156 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
48157 field.setFromData(sd);
48160 field.setValue(values[id]);
48164 if(this.trackResetOnLoad){
48165 field.originalValue = field.getValue();
48170 this.resetHasChanged();
48173 Roo.each(this.childForms || [], function (f) {
48174 f.setValues(values);
48175 f.resetHasChanged();
48182 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
48183 * they are returned as an array.
48184 * @param {Boolean} asString
48187 getValues : function(asString){
48188 if (this.childForms) {
48189 // copy values from the child forms
48190 Roo.each(this.childForms, function (f) {
48191 this.setValues(f.getValues());
48196 if (typeof(FormData) != 'undefined' && asString !== true) {
48197 // this relies on a 'recent' version of chrome apparently...
48199 var fd = (new FormData(this.el.dom)).entries();
48201 var ent = fd.next();
48202 while (!ent.done) {
48203 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
48214 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
48215 if(asString === true){
48218 return Roo.urlDecode(fs);
48222 * Returns the fields in this form as an object with key/value pairs.
48223 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48226 getFieldValues : function(with_hidden)
48228 if (this.childForms) {
48229 // copy values from the child forms
48230 // should this call getFieldValues - probably not as we do not currently copy
48231 // hidden fields when we generate..
48232 Roo.each(this.childForms, function (f) {
48233 this.setValues(f.getValues());
48238 this.items.each(function(f){
48239 if (!f.getName()) {
48242 var v = f.getValue();
48243 if (f.inputType =='radio') {
48244 if (typeof(ret[f.getName()]) == 'undefined') {
48245 ret[f.getName()] = ''; // empty..
48248 if (!f.el.dom.checked) {
48252 v = f.el.dom.value;
48256 // not sure if this supported any more..
48257 if ((typeof(v) == 'object') && f.getRawValue) {
48258 v = f.getRawValue() ; // dates..
48260 // combo boxes where name != hiddenName...
48261 if (f.name != f.getName()) {
48262 ret[f.name] = f.getRawValue();
48264 ret[f.getName()] = v;
48271 * Clears all invalid messages in this form.
48272 * @return {BasicForm} this
48274 clearInvalid : function(){
48275 this.items.each(function(f){
48279 Roo.each(this.childForms || [], function (f) {
48288 * Resets this form.
48289 * @return {BasicForm} this
48291 reset : function(){
48292 this.items.each(function(f){
48296 Roo.each(this.childForms || [], function (f) {
48299 this.resetHasChanged();
48305 * Add Roo.form components to this form.
48306 * @param {Field} field1
48307 * @param {Field} field2 (optional)
48308 * @param {Field} etc (optional)
48309 * @return {BasicForm} this
48312 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48318 * Removes a field from the items collection (does NOT remove its markup).
48319 * @param {Field} field
48320 * @return {BasicForm} this
48322 remove : function(field){
48323 this.items.remove(field);
48328 * Looks at the fields in this form, checks them for an id attribute,
48329 * and calls applyTo on the existing dom element with that id.
48330 * @return {BasicForm} this
48332 render : function(){
48333 this.items.each(function(f){
48334 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48342 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48343 * @param {Object} values
48344 * @return {BasicForm} this
48346 applyToFields : function(o){
48347 this.items.each(function(f){
48354 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48355 * @param {Object} values
48356 * @return {BasicForm} this
48358 applyIfToFields : function(o){
48359 this.items.each(function(f){
48367 Roo.BasicForm = Roo.form.BasicForm;
48369 Roo.apply(Roo.form.BasicForm, {
48383 intervalID : false,
48389 if(this.isApplied){
48394 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48395 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48396 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48397 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48400 this.maskEl.top.enableDisplayMode("block");
48401 this.maskEl.left.enableDisplayMode("block");
48402 this.maskEl.bottom.enableDisplayMode("block");
48403 this.maskEl.right.enableDisplayMode("block");
48405 Roo.get(document.body).on('click', function(){
48409 Roo.get(document.body).on('touchstart', function(){
48413 this.isApplied = true
48416 mask : function(form, target)
48420 this.target = target;
48422 if(!this.form.errorMask || !target.el){
48426 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48428 var ot = this.target.el.calcOffsetsTo(scrollable);
48430 var scrollTo = ot[1] - this.form.maskOffset;
48432 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48434 scrollable.scrollTo('top', scrollTo);
48436 var el = this.target.wrap || this.target.el;
48438 var box = el.getBox();
48440 this.maskEl.top.setStyle('position', 'absolute');
48441 this.maskEl.top.setStyle('z-index', 10000);
48442 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48443 this.maskEl.top.setLeft(0);
48444 this.maskEl.top.setTop(0);
48445 this.maskEl.top.show();
48447 this.maskEl.left.setStyle('position', 'absolute');
48448 this.maskEl.left.setStyle('z-index', 10000);
48449 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48450 this.maskEl.left.setLeft(0);
48451 this.maskEl.left.setTop(box.y - this.padding);
48452 this.maskEl.left.show();
48454 this.maskEl.bottom.setStyle('position', 'absolute');
48455 this.maskEl.bottom.setStyle('z-index', 10000);
48456 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48457 this.maskEl.bottom.setLeft(0);
48458 this.maskEl.bottom.setTop(box.bottom + this.padding);
48459 this.maskEl.bottom.show();
48461 this.maskEl.right.setStyle('position', 'absolute');
48462 this.maskEl.right.setStyle('z-index', 10000);
48463 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48464 this.maskEl.right.setLeft(box.right + this.padding);
48465 this.maskEl.right.setTop(box.y - this.padding);
48466 this.maskEl.right.show();
48468 this.intervalID = window.setInterval(function() {
48469 Roo.form.BasicForm.popover.unmask();
48472 window.onwheel = function(){ return false;};
48474 (function(){ this.isMasked = true; }).defer(500, this);
48478 unmask : function()
48480 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48484 this.maskEl.top.setStyle('position', 'absolute');
48485 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48486 this.maskEl.top.hide();
48488 this.maskEl.left.setStyle('position', 'absolute');
48489 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48490 this.maskEl.left.hide();
48492 this.maskEl.bottom.setStyle('position', 'absolute');
48493 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48494 this.maskEl.bottom.hide();
48496 this.maskEl.right.setStyle('position', 'absolute');
48497 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48498 this.maskEl.right.hide();
48500 window.onwheel = function(){ return true;};
48502 if(this.intervalID){
48503 window.clearInterval(this.intervalID);
48504 this.intervalID = false;
48507 this.isMasked = false;
48515 * Ext JS Library 1.1.1
48516 * Copyright(c) 2006-2007, Ext JS, LLC.
48518 * Originally Released Under LGPL - original licence link has changed is not relivant.
48521 * <script type="text/javascript">
48525 * @class Roo.form.Form
48526 * @extends Roo.form.BasicForm
48527 * @children Roo.form.Column Roo.form.FieldSet Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
48528 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48530 * @param {Object} config Configuration options
48532 Roo.form.Form = function(config){
48534 if (config.items) {
48535 xitems = config.items;
48536 delete config.items;
48540 Roo.form.Form.superclass.constructor.call(this, null, config);
48541 this.url = this.url || this.action;
48543 this.root = new Roo.form.Layout(Roo.applyIf({
48547 this.active = this.root;
48549 * Array of all the buttons that have been added to this form via {@link addButton}
48553 this.allItems = [];
48556 * @event clientvalidation
48557 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48558 * @param {Form} this
48559 * @param {Boolean} valid true if the form has passed client-side validation
48561 clientvalidation: true,
48564 * Fires when the form is rendered
48565 * @param {Roo.form.Form} form
48570 if (this.progressUrl) {
48571 // push a hidden field onto the list of fields..
48575 name : 'UPLOAD_IDENTIFIER'
48580 Roo.each(xitems, this.addxtype, this);
48584 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48586 * @cfg {Roo.Button} buttons[] buttons at bottom of form
48590 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48593 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48596 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48598 buttonAlign:'center',
48601 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48606 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48607 * This property cascades to child containers if not set.
48612 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48613 * fires a looping event with that state. This is required to bind buttons to the valid
48614 * state using the config value formBind:true on the button.
48616 monitorValid : false,
48619 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48624 * @cfg {String} progressUrl - Url to return progress data
48627 progressUrl : false,
48629 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48630 * sending a formdata with extra parameters - eg uploaded elements.
48636 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48637 * fields are added and the column is closed. If no fields are passed the column remains open
48638 * until end() is called.
48639 * @param {Object} config The config to pass to the column
48640 * @param {Field} field1 (optional)
48641 * @param {Field} field2 (optional)
48642 * @param {Field} etc (optional)
48643 * @return Column The column container object
48645 column : function(c){
48646 var col = new Roo.form.Column(c);
48648 if(arguments.length > 1){ // duplicate code required because of Opera
48649 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48656 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48657 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48658 * until end() is called.
48659 * @param {Object} config The config to pass to the fieldset
48660 * @param {Field} field1 (optional)
48661 * @param {Field} field2 (optional)
48662 * @param {Field} etc (optional)
48663 * @return FieldSet The fieldset container object
48665 fieldset : function(c){
48666 var fs = new Roo.form.FieldSet(c);
48668 if(arguments.length > 1){ // duplicate code required because of Opera
48669 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48676 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48677 * fields are added and the container is closed. If no fields are passed the container remains open
48678 * until end() is called.
48679 * @param {Object} config The config to pass to the Layout
48680 * @param {Field} field1 (optional)
48681 * @param {Field} field2 (optional)
48682 * @param {Field} etc (optional)
48683 * @return Layout The container object
48685 container : function(c){
48686 var l = new Roo.form.Layout(c);
48688 if(arguments.length > 1){ // duplicate code required because of Opera
48689 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48696 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48697 * @param {Object} container A Roo.form.Layout or subclass of Layout
48698 * @return {Form} this
48700 start : function(c){
48701 // cascade label info
48702 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48703 this.active.stack.push(c);
48704 c.ownerCt = this.active;
48710 * Closes the current open container
48711 * @return {Form} this
48714 if(this.active == this.root){
48717 this.active = this.active.ownerCt;
48722 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48723 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48724 * as the label of the field.
48725 * @param {Field} field1
48726 * @param {Field} field2 (optional)
48727 * @param {Field} etc. (optional)
48728 * @return {Form} this
48731 this.active.stack.push.apply(this.active.stack, arguments);
48732 this.allItems.push.apply(this.allItems,arguments);
48734 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48735 if(a[i].isFormField){
48740 Roo.form.Form.superclass.add.apply(this, r);
48750 * Find any element that has been added to a form, using it's ID or name
48751 * This can include framesets, columns etc. along with regular fields..
48752 * @param {String} id - id or name to find.
48754 * @return {Element} e - or false if nothing found.
48756 findbyId : function(id)
48762 Roo.each(this.allItems, function(f){
48763 if (f.id == id || f.name == id ){
48774 * Render this form into the passed container. This should only be called once!
48775 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48776 * @return {Form} this
48778 render : function(ct)
48784 var o = this.autoCreate || {
48786 method : this.method || 'POST',
48787 id : this.id || Roo.id()
48789 this.initEl(ct.createChild(o));
48791 this.root.render(this.el);
48795 this.items.each(function(f){
48796 f.render('x-form-el-'+f.id);
48799 if(this.buttons.length > 0){
48800 // tables are required to maintain order and for correct IE layout
48801 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48802 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48803 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48805 var tr = tb.getElementsByTagName('tr')[0];
48806 for(var i = 0, len = this.buttons.length; i < len; i++) {
48807 var b = this.buttons[i];
48808 var td = document.createElement('td');
48809 td.className = 'x-form-btn-td';
48810 b.render(tr.appendChild(td));
48813 if(this.monitorValid){ // initialize after render
48814 this.startMonitoring();
48816 this.fireEvent('rendered', this);
48821 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48822 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48823 * object or a valid Roo.DomHelper element config
48824 * @param {Function} handler The function called when the button is clicked
48825 * @param {Object} scope (optional) The scope of the handler function
48826 * @return {Roo.Button}
48828 addButton : function(config, handler, scope){
48832 minWidth: this.minButtonWidth,
48835 if(typeof config == "string"){
48838 Roo.apply(bc, config);
48840 var btn = new Roo.Button(null, bc);
48841 this.buttons.push(btn);
48846 * Adds a series of form elements (using the xtype property as the factory method.
48847 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48848 * @param {Object} config
48851 addxtype : function()
48853 var ar = Array.prototype.slice.call(arguments, 0);
48855 for(var i = 0; i < ar.length; i++) {
48857 continue; // skip -- if this happends something invalid got sent, we
48858 // should ignore it, as basically that interface element will not show up
48859 // and that should be pretty obvious!!
48862 if (Roo.form[ar[i].xtype]) {
48864 var fe = Roo.factory(ar[i], Roo.form);
48870 fe.store.form = this;
48875 this.allItems.push(fe);
48876 if (fe.items && fe.addxtype) {
48877 fe.addxtype.apply(fe, fe.items);
48887 // console.log('adding ' + ar[i].xtype);
48889 if (ar[i].xtype == 'Button') {
48890 //console.log('adding button');
48891 //console.log(ar[i]);
48892 this.addButton(ar[i]);
48893 this.allItems.push(fe);
48897 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48898 alert('end is not supported on xtype any more, use items');
48900 // //console.log('adding end');
48908 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48909 * option "monitorValid"
48911 startMonitoring : function(){
48914 Roo.TaskMgr.start({
48915 run : this.bindHandler,
48916 interval : this.monitorPoll || 200,
48923 * Stops monitoring of the valid state of this form
48925 stopMonitoring : function(){
48926 this.bound = false;
48930 bindHandler : function(){
48932 return false; // stops binding
48935 this.items.each(function(f){
48936 if(!f.isValid(true)){
48941 for(var i = 0, len = this.buttons.length; i < len; i++){
48942 var btn = this.buttons[i];
48943 if(btn.formBind === true && btn.disabled === valid){
48944 btn.setDisabled(!valid);
48947 this.fireEvent('clientvalidation', this, valid);
48961 Roo.Form = Roo.form.Form;
48964 * Ext JS Library 1.1.1
48965 * Copyright(c) 2006-2007, Ext JS, LLC.
48967 * Originally Released Under LGPL - original licence link has changed is not relivant.
48970 * <script type="text/javascript">
48973 // as we use this in bootstrap.
48974 Roo.namespace('Roo.form');
48976 * @class Roo.form.Action
48977 * Internal Class used to handle form actions
48979 * @param {Roo.form.BasicForm} el The form element or its id
48980 * @param {Object} config Configuration options
48985 // define the action interface
48986 Roo.form.Action = function(form, options){
48988 this.options = options || {};
48991 * Client Validation Failed
48994 Roo.form.Action.CLIENT_INVALID = 'client';
48996 * Server Validation Failed
48999 Roo.form.Action.SERVER_INVALID = 'server';
49001 * Connect to Server Failed
49004 Roo.form.Action.CONNECT_FAILURE = 'connect';
49006 * Reading Data from Server Failed
49009 Roo.form.Action.LOAD_FAILURE = 'load';
49011 Roo.form.Action.prototype = {
49013 failureType : undefined,
49014 response : undefined,
49015 result : undefined,
49017 // interface method
49018 run : function(options){
49022 // interface method
49023 success : function(response){
49027 // interface method
49028 handleResponse : function(response){
49032 // default connection failure
49033 failure : function(response){
49035 this.response = response;
49036 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49037 this.form.afterAction(this, false);
49040 processResponse : function(response){
49041 this.response = response;
49042 if(!response.responseText){
49045 this.result = this.handleResponse(response);
49046 return this.result;
49049 // utility functions used internally
49050 getUrl : function(appendParams){
49051 var url = this.options.url || this.form.url || this.form.el.dom.action;
49053 var p = this.getParams();
49055 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
49061 getMethod : function(){
49062 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
49065 getParams : function(){
49066 var bp = this.form.baseParams;
49067 var p = this.options.params;
49069 if(typeof p == "object"){
49070 p = Roo.urlEncode(Roo.applyIf(p, bp));
49071 }else if(typeof p == 'string' && bp){
49072 p += '&' + Roo.urlEncode(bp);
49075 p = Roo.urlEncode(bp);
49080 createCallback : function(){
49082 success: this.success,
49083 failure: this.failure,
49085 timeout: (this.form.timeout*1000),
49086 upload: this.form.fileUpload ? this.success : undefined
49091 Roo.form.Action.Submit = function(form, options){
49092 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
49095 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
49098 haveProgress : false,
49099 uploadComplete : false,
49101 // uploadProgress indicator.
49102 uploadProgress : function()
49104 if (!this.form.progressUrl) {
49108 if (!this.haveProgress) {
49109 Roo.MessageBox.progress("Uploading", "Uploading");
49111 if (this.uploadComplete) {
49112 Roo.MessageBox.hide();
49116 this.haveProgress = true;
49118 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
49120 var c = new Roo.data.Connection();
49122 url : this.form.progressUrl,
49127 success : function(req){
49128 //console.log(data);
49132 rdata = Roo.decode(req.responseText)
49134 Roo.log("Invalid data from server..");
49138 if (!rdata || !rdata.success) {
49140 Roo.MessageBox.alert(Roo.encode(rdata));
49143 var data = rdata.data;
49145 if (this.uploadComplete) {
49146 Roo.MessageBox.hide();
49151 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
49152 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
49155 this.uploadProgress.defer(2000,this);
49158 failure: function(data) {
49159 Roo.log('progress url failed ');
49170 // run get Values on the form, so it syncs any secondary forms.
49171 this.form.getValues();
49173 var o = this.options;
49174 var method = this.getMethod();
49175 var isPost = method == 'POST';
49176 if(o.clientValidation === false || this.form.isValid()){
49178 if (this.form.progressUrl) {
49179 this.form.findField('UPLOAD_IDENTIFIER').setValue(
49180 (new Date() * 1) + '' + Math.random());
49185 Roo.Ajax.request(Roo.apply(this.createCallback(), {
49186 form:this.form.el.dom,
49187 url:this.getUrl(!isPost),
49189 params:isPost ? this.getParams() : null,
49190 isUpload: this.form.fileUpload,
49191 formData : this.form.formData
49194 this.uploadProgress();
49196 }else if (o.clientValidation !== false){ // client validation failed
49197 this.failureType = Roo.form.Action.CLIENT_INVALID;
49198 this.form.afterAction(this, false);
49202 success : function(response)
49204 this.uploadComplete= true;
49205 if (this.haveProgress) {
49206 Roo.MessageBox.hide();
49210 var result = this.processResponse(response);
49211 if(result === true || result.success){
49212 this.form.afterAction(this, true);
49216 this.form.markInvalid(result.errors);
49217 this.failureType = Roo.form.Action.SERVER_INVALID;
49219 this.form.afterAction(this, false);
49221 failure : function(response)
49223 this.uploadComplete= true;
49224 if (this.haveProgress) {
49225 Roo.MessageBox.hide();
49228 this.response = response;
49229 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49230 this.form.afterAction(this, false);
49233 handleResponse : function(response){
49234 if(this.form.errorReader){
49235 var rs = this.form.errorReader.read(response);
49238 for(var i = 0, len = rs.records.length; i < len; i++) {
49239 var r = rs.records[i];
49240 errors[i] = r.data;
49243 if(errors.length < 1){
49247 success : rs.success,
49253 ret = Roo.decode(response.responseText);
49257 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49267 Roo.form.Action.Load = function(form, options){
49268 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49269 this.reader = this.form.reader;
49272 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49277 Roo.Ajax.request(Roo.apply(
49278 this.createCallback(), {
49279 method:this.getMethod(),
49280 url:this.getUrl(false),
49281 params:this.getParams()
49285 success : function(response){
49287 var result = this.processResponse(response);
49288 if(result === true || !result.success || !result.data){
49289 this.failureType = Roo.form.Action.LOAD_FAILURE;
49290 this.form.afterAction(this, false);
49293 this.form.clearInvalid();
49294 this.form.setValues(result.data);
49295 this.form.afterAction(this, true);
49298 handleResponse : function(response){
49299 if(this.form.reader){
49300 var rs = this.form.reader.read(response);
49301 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49303 success : rs.success,
49307 return Roo.decode(response.responseText);
49311 Roo.form.Action.ACTION_TYPES = {
49312 'load' : Roo.form.Action.Load,
49313 'submit' : Roo.form.Action.Submit
49316 * Ext JS Library 1.1.1
49317 * Copyright(c) 2006-2007, Ext JS, LLC.
49319 * Originally Released Under LGPL - original licence link has changed is not relivant.
49322 * <script type="text/javascript">
49326 * @class Roo.form.Layout
49327 * @extends Roo.Component
49328 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49329 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49331 * @param {Object} config Configuration options
49333 Roo.form.Layout = function(config){
49335 if (config.items) {
49336 xitems = config.items;
49337 delete config.items;
49339 Roo.form.Layout.superclass.constructor.call(this, config);
49341 Roo.each(xitems, this.addxtype, this);
49345 Roo.extend(Roo.form.Layout, Roo.Component, {
49347 * @cfg {String/Object} autoCreate
49348 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49351 * @cfg {String/Object/Function} style
49352 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49353 * a function which returns such a specification.
49356 * @cfg {String} labelAlign
49357 * Valid values are "left," "top" and "right" (defaults to "left")
49360 * @cfg {Number} labelWidth
49361 * Fixed width in pixels of all field labels (defaults to undefined)
49364 * @cfg {Boolean} clear
49365 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49369 * @cfg {String} labelSeparator
49370 * The separator to use after field labels (defaults to ':')
49372 labelSeparator : ':',
49374 * @cfg {Boolean} hideLabels
49375 * True to suppress the display of field labels in this layout (defaults to false)
49377 hideLabels : false,
49380 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49385 onRender : function(ct, position){
49386 if(this.el){ // from markup
49387 this.el = Roo.get(this.el);
49388 }else { // generate
49389 var cfg = this.getAutoCreate();
49390 this.el = ct.createChild(cfg, position);
49393 this.el.applyStyles(this.style);
49395 if(this.labelAlign){
49396 this.el.addClass('x-form-label-'+this.labelAlign);
49398 if(this.hideLabels){
49399 this.labelStyle = "display:none";
49400 this.elementStyle = "padding-left:0;";
49402 if(typeof this.labelWidth == 'number'){
49403 this.labelStyle = "width:"+this.labelWidth+"px;";
49404 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49406 if(this.labelAlign == 'top'){
49407 this.labelStyle = "width:auto;";
49408 this.elementStyle = "padding-left:0;";
49411 var stack = this.stack;
49412 var slen = stack.length;
49414 if(!this.fieldTpl){
49415 var t = new Roo.Template(
49416 '<div class="x-form-item {5}">',
49417 '<label for="{0}" style="{2}">{1}{4}</label>',
49418 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49420 '</div><div class="x-form-clear-left"></div>'
49422 t.disableFormats = true;
49424 Roo.form.Layout.prototype.fieldTpl = t;
49426 for(var i = 0; i < slen; i++) {
49427 if(stack[i].isFormField){
49428 this.renderField(stack[i]);
49430 this.renderComponent(stack[i]);
49435 this.el.createChild({cls:'x-form-clear'});
49440 renderField : function(f){
49441 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49444 f.labelStyle||this.labelStyle||'', //2
49445 this.elementStyle||'', //3
49446 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49447 f.itemCls||this.itemCls||'' //5
49448 ], true).getPrevSibling());
49452 renderComponent : function(c){
49453 c.render(c.isLayout ? this.el : this.el.createChild());
49456 * Adds a object form elements (using the xtype property as the factory method.)
49457 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49458 * @param {Object} config
49460 addxtype : function(o)
49462 // create the lement.
49463 o.form = this.form;
49464 var fe = Roo.factory(o, Roo.form);
49465 this.form.allItems.push(fe);
49466 this.stack.push(fe);
49468 if (fe.isFormField) {
49469 this.form.items.add(fe);
49477 * @class Roo.form.Column
49478 * @extends Roo.form.Layout
49479 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49481 * @param {Object} config Configuration options
49483 Roo.form.Column = function(config){
49484 Roo.form.Column.superclass.constructor.call(this, config);
49487 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49489 * @cfg {Number/String} width
49490 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49493 * @cfg {String/Object} autoCreate
49494 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49498 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49501 onRender : function(ct, position){
49502 Roo.form.Column.superclass.onRender.call(this, ct, position);
49504 this.el.setWidth(this.width);
49511 * @class Roo.form.Row
49512 * @extends Roo.form.Layout
49513 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49514 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49516 * @param {Object} config Configuration options
49520 Roo.form.Row = function(config){
49521 Roo.form.Row.superclass.constructor.call(this, config);
49524 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49526 * @cfg {Number/String} width
49527 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49530 * @cfg {Number/String} height
49531 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49533 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49537 onRender : function(ct, position){
49538 //console.log('row render');
49540 var t = new Roo.Template(
49541 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49542 '<label for="{0}" style="{2}">{1}{4}</label>',
49543 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49547 t.disableFormats = true;
49549 Roo.form.Layout.prototype.rowTpl = t;
49551 this.fieldTpl = this.rowTpl;
49553 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49554 var labelWidth = 100;
49556 if ((this.labelAlign != 'top')) {
49557 if (typeof this.labelWidth == 'number') {
49558 labelWidth = this.labelWidth
49560 this.padWidth = 20 + labelWidth;
49564 Roo.form.Column.superclass.onRender.call(this, ct, position);
49566 this.el.setWidth(this.width);
49569 this.el.setHeight(this.height);
49574 renderField : function(f){
49575 f.fieldEl = this.fieldTpl.append(this.el, [
49576 f.id, f.fieldLabel,
49577 f.labelStyle||this.labelStyle||'',
49578 this.elementStyle||'',
49579 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49580 f.itemCls||this.itemCls||'',
49581 f.width ? f.width + this.padWidth : 160 + this.padWidth
49588 * @class Roo.form.FieldSet
49589 * @extends Roo.form.Layout
49590 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49591 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49593 * @param {Object} config Configuration options
49595 Roo.form.FieldSet = function(config){
49596 Roo.form.FieldSet.superclass.constructor.call(this, config);
49599 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49601 * @cfg {String} legend
49602 * The text to display as the legend for the FieldSet (defaults to '')
49605 * @cfg {String/Object} autoCreate
49606 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49610 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49613 onRender : function(ct, position){
49614 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49616 this.setLegend(this.legend);
49621 setLegend : function(text){
49623 this.el.child('legend').update(text);
49628 * Ext JS Library 1.1.1
49629 * Copyright(c) 2006-2007, Ext JS, LLC.
49631 * Originally Released Under LGPL - original licence link has changed is not relivant.
49634 * <script type="text/javascript">
49637 * @class Roo.form.VTypes
49638 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49641 Roo.form.VTypes = function(){
49642 // closure these in so they are only created once.
49643 var alpha = /^[a-zA-Z_]+$/;
49644 var alphanum = /^[a-zA-Z0-9_]+$/;
49645 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49646 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49648 // All these messages and functions are configurable
49651 * The function used to validate email addresses
49652 * @param {String} value The email address
49654 'email' : function(v){
49655 return email.test(v);
49658 * The error text to display when the email validation function returns false
49661 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49663 * The keystroke filter mask to be applied on email input
49666 'emailMask' : /[a-z0-9_\.\-@]/i,
49669 * The function used to validate URLs
49670 * @param {String} value The URL
49672 'url' : function(v){
49673 return url.test(v);
49676 * The error text to display when the url validation function returns false
49679 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49682 * The function used to validate alpha values
49683 * @param {String} value The value
49685 'alpha' : function(v){
49686 return alpha.test(v);
49689 * The error text to display when the alpha validation function returns false
49692 'alphaText' : 'This field should only contain letters and _',
49694 * The keystroke filter mask to be applied on alpha input
49697 'alphaMask' : /[a-z_]/i,
49700 * The function used to validate alphanumeric values
49701 * @param {String} value The value
49703 'alphanum' : function(v){
49704 return alphanum.test(v);
49707 * The error text to display when the alphanumeric validation function returns false
49710 'alphanumText' : 'This field should only contain letters, numbers and _',
49712 * The keystroke filter mask to be applied on alphanumeric input
49715 'alphanumMask' : /[a-z0-9_]/i
49717 }();//<script type="text/javascript">
49720 * @class Roo.form.FCKeditor
49721 * @extends Roo.form.TextArea
49722 * Wrapper around the FCKEditor http://www.fckeditor.net
49724 * Creates a new FCKeditor
49725 * @param {Object} config Configuration options
49727 Roo.form.FCKeditor = function(config){
49728 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49731 * @event editorinit
49732 * Fired when the editor is initialized - you can add extra handlers here..
49733 * @param {FCKeditor} this
49734 * @param {Object} the FCK object.
49741 Roo.form.FCKeditor.editors = { };
49742 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49744 //defaultAutoCreate : {
49745 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49749 * @cfg {Object} fck options - see fck manual for details.
49754 * @cfg {Object} fck toolbar set (Basic or Default)
49756 toolbarSet : 'Basic',
49758 * @cfg {Object} fck BasePath
49760 basePath : '/fckeditor/',
49768 onRender : function(ct, position)
49771 this.defaultAutoCreate = {
49773 style:"width:300px;height:60px;",
49774 autocomplete: "new-password"
49777 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49780 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49781 if(this.preventScrollbars){
49782 this.el.setStyle("overflow", "hidden");
49784 this.el.setHeight(this.growMin);
49787 //console.log('onrender' + this.getId() );
49788 Roo.form.FCKeditor.editors[this.getId()] = this;
49791 this.replaceTextarea() ;
49795 getEditor : function() {
49796 return this.fckEditor;
49799 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49800 * @param {Mixed} value The value to set
49804 setValue : function(value)
49806 //console.log('setValue: ' + value);
49808 if(typeof(value) == 'undefined') { // not sure why this is happending...
49811 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49813 //if(!this.el || !this.getEditor()) {
49814 // this.value = value;
49815 //this.setValue.defer(100,this,[value]);
49819 if(!this.getEditor()) {
49823 this.getEditor().SetData(value);
49830 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49831 * @return {Mixed} value The field value
49833 getValue : function()
49836 if (this.frame && this.frame.dom.style.display == 'none') {
49837 return Roo.form.FCKeditor.superclass.getValue.call(this);
49840 if(!this.el || !this.getEditor()) {
49842 // this.getValue.defer(100,this);
49847 var value=this.getEditor().GetData();
49848 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49849 return Roo.form.FCKeditor.superclass.getValue.call(this);
49855 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49856 * @return {Mixed} value The field value
49858 getRawValue : function()
49860 if (this.frame && this.frame.dom.style.display == 'none') {
49861 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49864 if(!this.el || !this.getEditor()) {
49865 //this.getRawValue.defer(100,this);
49872 var value=this.getEditor().GetData();
49873 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49874 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49878 setSize : function(w,h) {
49882 //if (this.frame && this.frame.dom.style.display == 'none') {
49883 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49886 //if(!this.el || !this.getEditor()) {
49887 // this.setSize.defer(100,this, [w,h]);
49893 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49895 this.frame.dom.setAttribute('width', w);
49896 this.frame.dom.setAttribute('height', h);
49897 this.frame.setSize(w,h);
49901 toggleSourceEdit : function(value) {
49905 this.el.dom.style.display = value ? '' : 'none';
49906 this.frame.dom.style.display = value ? 'none' : '';
49911 focus: function(tag)
49913 if (this.frame.dom.style.display == 'none') {
49914 return Roo.form.FCKeditor.superclass.focus.call(this);
49916 if(!this.el || !this.getEditor()) {
49917 this.focus.defer(100,this, [tag]);
49924 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49925 this.getEditor().Focus();
49927 if (!this.getEditor().Selection.GetSelection()) {
49928 this.focus.defer(100,this, [tag]);
49933 var r = this.getEditor().EditorDocument.createRange();
49934 r.setStart(tgs[0],0);
49935 r.setEnd(tgs[0],0);
49936 this.getEditor().Selection.GetSelection().removeAllRanges();
49937 this.getEditor().Selection.GetSelection().addRange(r);
49938 this.getEditor().Focus();
49945 replaceTextarea : function()
49947 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49950 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49952 // We must check the elements firstly using the Id and then the name.
49953 var oTextarea = document.getElementById( this.getId() );
49955 var colElementsByName = document.getElementsByName( this.getId() ) ;
49957 oTextarea.style.display = 'none' ;
49959 if ( oTextarea.tabIndex ) {
49960 this.TabIndex = oTextarea.tabIndex ;
49963 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49964 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49965 this.frame = Roo.get(this.getId() + '___Frame')
49968 _getConfigHtml : function()
49972 for ( var o in this.fckconfig ) {
49973 sConfig += sConfig.length > 0 ? '&' : '';
49974 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49977 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49981 _getIFrameHtml : function()
49983 var sFile = 'fckeditor.html' ;
49984 /* no idea what this is about..
49987 if ( (/fcksource=true/i).test( window.top.location.search ) )
49988 sFile = 'fckeditor.original.html' ;
49993 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49994 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49997 var html = '<iframe id="' + this.getId() +
49998 '___Frame" src="' + sLink +
49999 '" width="' + this.width +
50000 '" height="' + this.height + '"' +
50001 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
50002 ' frameborder="0" scrolling="no"></iframe>' ;
50007 _insertHtmlBefore : function( html, element )
50009 if ( element.insertAdjacentHTML ) {
50011 element.insertAdjacentHTML( 'beforeBegin', html ) ;
50013 var oRange = document.createRange() ;
50014 oRange.setStartBefore( element ) ;
50015 var oFragment = oRange.createContextualFragment( html );
50016 element.parentNode.insertBefore( oFragment, element ) ;
50029 //Roo.reg('fckeditor', Roo.form.FCKeditor);
50031 function FCKeditor_OnComplete(editorInstance){
50032 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
50033 f.fckEditor = editorInstance;
50034 //console.log("loaded");
50035 f.fireEvent('editorinit', f, editorInstance);
50055 //<script type="text/javascript">
50057 * @class Roo.form.GridField
50058 * @extends Roo.form.Field
50059 * Embed a grid (or editable grid into a form)
50062 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
50064 * xgrid.store = Roo.data.Store
50065 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
50066 * xgrid.store.reader = Roo.data.JsonReader
50070 * Creates a new GridField
50071 * @param {Object} config Configuration options
50073 Roo.form.GridField = function(config){
50074 Roo.form.GridField.superclass.constructor.call(this, config);
50078 Roo.extend(Roo.form.GridField, Roo.form.Field, {
50080 * @cfg {Number} width - used to restrict width of grid..
50084 * @cfg {Number} height - used to restrict height of grid..
50088 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
50094 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50095 * {tag: "input", type: "checkbox", autocomplete: "off"})
50097 // defaultAutoCreate : { tag: 'div' },
50098 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
50100 * @cfg {String} addTitle Text to include for adding a title.
50104 onResize : function(){
50105 Roo.form.Field.superclass.onResize.apply(this, arguments);
50108 initEvents : function(){
50109 // Roo.form.Checkbox.superclass.initEvents.call(this);
50110 // has no events...
50115 getResizeEl : function(){
50119 getPositionEl : function(){
50124 onRender : function(ct, position){
50126 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
50127 var style = this.style;
50130 Roo.form.GridField.superclass.onRender.call(this, ct, position);
50131 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
50132 this.viewEl = this.wrap.createChild({ tag: 'div' });
50134 this.viewEl.applyStyles(style);
50137 this.viewEl.setWidth(this.width);
50140 this.viewEl.setHeight(this.height);
50142 //if(this.inputValue !== undefined){
50143 //this.setValue(this.value);
50146 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
50149 this.grid.render();
50150 this.grid.getDataSource().on('remove', this.refreshValue, this);
50151 this.grid.getDataSource().on('update', this.refreshValue, this);
50152 this.grid.on('afteredit', this.refreshValue, this);
50158 * Sets the value of the item.
50159 * @param {String} either an object or a string..
50161 setValue : function(v){
50163 v = v || []; // empty set..
50164 // this does not seem smart - it really only affects memoryproxy grids..
50165 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
50166 var ds = this.grid.getDataSource();
50167 // assumes a json reader..
50169 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
50170 ds.loadData( data);
50172 // clear selection so it does not get stale.
50173 if (this.grid.sm) {
50174 this.grid.sm.clearSelections();
50177 Roo.form.GridField.superclass.setValue.call(this, v);
50178 this.refreshValue();
50179 // should load data in the grid really....
50183 refreshValue: function() {
50185 this.grid.getDataSource().each(function(r) {
50188 this.el.dom.value = Roo.encode(val);
50196 * Ext JS Library 1.1.1
50197 * Copyright(c) 2006-2007, Ext JS, LLC.
50199 * Originally Released Under LGPL - original licence link has changed is not relivant.
50202 * <script type="text/javascript">
50205 * @class Roo.form.DisplayField
50206 * @extends Roo.form.Field
50207 * A generic Field to display non-editable data.
50208 * @cfg {Boolean} closable (true|false) default false
50210 * Creates a new Display Field item.
50211 * @param {Object} config Configuration options
50213 Roo.form.DisplayField = function(config){
50214 Roo.form.DisplayField.superclass.constructor.call(this, config);
50219 * Fires after the click the close btn
50220 * @param {Roo.form.DisplayField} this
50226 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50227 inputType: 'hidden',
50233 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50235 focusClass : undefined,
50237 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50239 fieldClass: 'x-form-field',
50242 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50244 valueRenderer: undefined,
50248 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50249 * {tag: "input", type: "checkbox", autocomplete: "off"})
50252 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50256 onResize : function(){
50257 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50261 initEvents : function(){
50262 // Roo.form.Checkbox.superclass.initEvents.call(this);
50263 // has no events...
50266 this.closeEl.on('click', this.onClose, this);
50272 getResizeEl : function(){
50276 getPositionEl : function(){
50281 onRender : function(ct, position){
50283 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50284 //if(this.inputValue !== undefined){
50285 this.wrap = this.el.wrap();
50287 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50290 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50293 if (this.bodyStyle) {
50294 this.viewEl.applyStyles(this.bodyStyle);
50296 //this.viewEl.setStyle('padding', '2px');
50298 this.setValue(this.value);
50303 initValue : Roo.emptyFn,
50308 onClick : function(){
50313 * Sets the checked state of the checkbox.
50314 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50316 setValue : function(v){
50318 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50319 // this might be called before we have a dom element..
50320 if (!this.viewEl) {
50323 this.viewEl.dom.innerHTML = html;
50324 Roo.form.DisplayField.superclass.setValue.call(this, v);
50328 onClose : function(e)
50330 e.preventDefault();
50332 this.fireEvent('close', this);
50341 * @class Roo.form.DayPicker
50342 * @extends Roo.form.Field
50343 * A Day picker show [M] [T] [W] ....
50345 * Creates a new Day Picker
50346 * @param {Object} config Configuration options
50348 Roo.form.DayPicker= function(config){
50349 Roo.form.DayPicker.superclass.constructor.call(this, config);
50353 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50355 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50357 focusClass : undefined,
50359 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50361 fieldClass: "x-form-field",
50364 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50365 * {tag: "input", type: "checkbox", autocomplete: "off"})
50367 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50370 actionMode : 'viewEl',
50374 inputType : 'hidden',
50377 inputElement: false, // real input element?
50378 basedOn: false, // ????
50380 isFormField: true, // not sure where this is needed!!!!
50382 onResize : function(){
50383 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50384 if(!this.boxLabel){
50385 this.el.alignTo(this.wrap, 'c-c');
50389 initEvents : function(){
50390 Roo.form.Checkbox.superclass.initEvents.call(this);
50391 this.el.on("click", this.onClick, this);
50392 this.el.on("change", this.onClick, this);
50396 getResizeEl : function(){
50400 getPositionEl : function(){
50406 onRender : function(ct, position){
50407 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50409 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50411 var r1 = '<table><tr>';
50412 var r2 = '<tr class="x-form-daypick-icons">';
50413 for (var i=0; i < 7; i++) {
50414 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50415 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50418 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50419 viewEl.select('img').on('click', this.onClick, this);
50420 this.viewEl = viewEl;
50423 // this will not work on Chrome!!!
50424 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50425 this.el.on('propertychange', this.setFromHidden, this); //ie
50433 initValue : Roo.emptyFn,
50436 * Returns the checked state of the checkbox.
50437 * @return {Boolean} True if checked, else false
50439 getValue : function(){
50440 return this.el.dom.value;
50445 onClick : function(e){
50446 //this.setChecked(!this.checked);
50447 Roo.get(e.target).toggleClass('x-menu-item-checked');
50448 this.refreshValue();
50449 //if(this.el.dom.checked != this.checked){
50450 // this.setValue(this.el.dom.checked);
50455 refreshValue : function()
50458 this.viewEl.select('img',true).each(function(e,i,n) {
50459 val += e.is(".x-menu-item-checked") ? String(n) : '';
50461 this.setValue(val, true);
50465 * Sets the checked state of the checkbox.
50466 * On is always based on a string comparison between inputValue and the param.
50467 * @param {Boolean/String} value - the value to set
50468 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50470 setValue : function(v,suppressEvent){
50471 if (!this.el.dom) {
50474 var old = this.el.dom.value ;
50475 this.el.dom.value = v;
50476 if (suppressEvent) {
50480 // update display..
50481 this.viewEl.select('img',true).each(function(e,i,n) {
50483 var on = e.is(".x-menu-item-checked");
50484 var newv = v.indexOf(String(n)) > -1;
50486 e.toggleClass('x-menu-item-checked');
50492 this.fireEvent('change', this, v, old);
50497 // handle setting of hidden value by some other method!!?!?
50498 setFromHidden: function()
50503 //console.log("SET FROM HIDDEN");
50504 //alert('setFrom hidden');
50505 this.setValue(this.el.dom.value);
50508 onDestroy : function()
50511 Roo.get(this.viewEl).remove();
50514 Roo.form.DayPicker.superclass.onDestroy.call(this);
50518 * RooJS Library 1.1.1
50519 * Copyright(c) 2008-2011 Alan Knowles
50526 * @class Roo.form.ComboCheck
50527 * @extends Roo.form.ComboBox
50528 * A combobox for multiple select items.
50530 * FIXME - could do with a reset button..
50533 * Create a new ComboCheck
50534 * @param {Object} config Configuration options
50536 Roo.form.ComboCheck = function(config){
50537 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50538 // should verify some data...
50540 // hiddenName = required..
50541 // displayField = required
50542 // valudField == required
50543 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50545 Roo.each(req, function(e) {
50546 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50547 throw "Roo.form.ComboCheck : missing value for: " + e;
50554 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50559 selectedClass: 'x-menu-item-checked',
50562 onRender : function(ct, position){
50568 var cls = 'x-combo-list';
50571 this.tpl = new Roo.Template({
50572 html : '<div class="'+cls+'-item x-menu-check-item">' +
50573 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50574 '<span>{' + this.displayField + '}</span>' +
50581 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50582 this.view.singleSelect = false;
50583 this.view.multiSelect = true;
50584 this.view.toggleSelect = true;
50585 this.pageTb.add(new Roo.Toolbar.Fill(), {
50588 handler: function()
50595 onViewOver : function(e, t){
50601 onViewClick : function(doFocus,index){
50605 select: function () {
50606 //Roo.log("SELECT CALLED");
50609 selectByValue : function(xv, scrollIntoView){
50610 var ar = this.getValueArray();
50613 Roo.each(ar, function(v) {
50614 if(v === undefined || v === null){
50617 var r = this.findRecord(this.valueField, v);
50619 sels.push(this.store.indexOf(r))
50623 this.view.select(sels);
50629 onSelect : function(record, index){
50630 // Roo.log("onselect Called");
50631 // this is only called by the clear button now..
50632 this.view.clearSelections();
50633 this.setValue('[]');
50634 if (this.value != this.valueBefore) {
50635 this.fireEvent('change', this, this.value, this.valueBefore);
50636 this.valueBefore = this.value;
50639 getValueArray : function()
50644 //Roo.log(this.value);
50645 if (typeof(this.value) == 'undefined') {
50648 var ar = Roo.decode(this.value);
50649 return ar instanceof Array ? ar : []; //?? valid?
50652 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50657 expand : function ()
50660 Roo.form.ComboCheck.superclass.expand.call(this);
50661 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50662 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50667 collapse : function(){
50668 Roo.form.ComboCheck.superclass.collapse.call(this);
50669 var sl = this.view.getSelectedIndexes();
50670 var st = this.store;
50674 Roo.each(sl, function(i) {
50676 nv.push(r.get(this.valueField));
50678 this.setValue(Roo.encode(nv));
50679 if (this.value != this.valueBefore) {
50681 this.fireEvent('change', this, this.value, this.valueBefore);
50682 this.valueBefore = this.value;
50687 setValue : function(v){
50691 var vals = this.getValueArray();
50693 Roo.each(vals, function(k) {
50694 var r = this.findRecord(this.valueField, k);
50696 tv.push(r.data[this.displayField]);
50697 }else if(this.valueNotFoundText !== undefined){
50698 tv.push( this.valueNotFoundText );
50703 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50704 this.hiddenField.value = v;
50710 * Ext JS Library 1.1.1
50711 * Copyright(c) 2006-2007, Ext JS, LLC.
50713 * Originally Released Under LGPL - original licence link has changed is not relivant.
50716 * <script type="text/javascript">
50720 * @class Roo.form.Signature
50721 * @extends Roo.form.Field
50725 * @param {Object} config Configuration options
50728 Roo.form.Signature = function(config){
50729 Roo.form.Signature.superclass.constructor.call(this, config);
50731 this.addEvents({// not in used??
50734 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50735 * @param {Roo.form.Signature} combo This combo box
50740 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50741 * @param {Roo.form.ComboBox} combo This combo box
50742 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50748 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50750 * @cfg {Object} labels Label to use when rendering a form.
50754 * confirm : "Confirm"
50759 confirm : "Confirm"
50762 * @cfg {Number} width The signature panel width (defaults to 300)
50766 * @cfg {Number} height The signature panel height (defaults to 100)
50770 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50772 allowBlank : false,
50775 // {Object} signPanel The signature SVG panel element (defaults to {})
50777 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50778 isMouseDown : false,
50779 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50780 isConfirmed : false,
50781 // {String} signatureTmp SVG mapping string (defaults to empty string)
50785 defaultAutoCreate : { // modified by initCompnoent..
50791 onRender : function(ct, position){
50793 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50795 this.wrap = this.el.wrap({
50796 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50799 this.createToolbar(this);
50800 this.signPanel = this.wrap.createChild({
50802 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50806 this.svgID = Roo.id();
50807 this.svgEl = this.signPanel.createChild({
50808 xmlns : 'http://www.w3.org/2000/svg',
50810 id : this.svgID + "-svg",
50812 height: this.height,
50813 viewBox: '0 0 '+this.width+' '+this.height,
50817 id: this.svgID + "-svg-r",
50819 height: this.height,
50824 id: this.svgID + "-svg-l",
50826 y1: (this.height*0.8), // start set the line in 80% of height
50827 x2: this.width, // end
50828 y2: (this.height*0.8), // end set the line in 80% of height
50830 'stroke-width': "1",
50831 'stroke-dasharray': "3",
50832 'shape-rendering': "crispEdges",
50833 'pointer-events': "none"
50837 id: this.svgID + "-svg-p",
50839 'stroke-width': "3",
50841 'pointer-events': 'none'
50846 this.svgBox = this.svgEl.dom.getScreenCTM();
50848 createSVG : function(){
50849 var svg = this.signPanel;
50850 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50853 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50854 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50855 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50856 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50857 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50858 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50859 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50862 isTouchEvent : function(e){
50863 return e.type.match(/^touch/);
50865 getCoords : function (e) {
50866 var pt = this.svgEl.dom.createSVGPoint();
50869 if (this.isTouchEvent(e)) {
50870 pt.x = e.targetTouches[0].clientX;
50871 pt.y = e.targetTouches[0].clientY;
50873 var a = this.svgEl.dom.getScreenCTM();
50874 var b = a.inverse();
50875 var mx = pt.matrixTransform(b);
50876 return mx.x + ',' + mx.y;
50878 //mouse event headler
50879 down : function (e) {
50880 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50881 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50883 this.isMouseDown = true;
50885 e.preventDefault();
50887 move : function (e) {
50888 if (this.isMouseDown) {
50889 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50890 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50893 e.preventDefault();
50895 up : function (e) {
50896 this.isMouseDown = false;
50897 var sp = this.signatureTmp.split(' ');
50900 if(!sp[sp.length-2].match(/^L/)){
50904 this.signatureTmp = sp.join(" ");
50907 if(this.getValue() != this.signatureTmp){
50908 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50909 this.isConfirmed = false;
50911 e.preventDefault();
50915 * Protected method that will not generally be called directly. It
50916 * is called when the editor creates its toolbar. Override this method if you need to
50917 * add custom toolbar buttons.
50918 * @param {HtmlEditor} editor
50920 createToolbar : function(editor){
50921 function btn(id, toggle, handler){
50922 var xid = fid + '-'+ id ;
50926 cls : 'x-btn-icon x-edit-'+id,
50927 enableToggle:toggle !== false,
50928 scope: editor, // was editor...
50929 handler:handler||editor.relayBtnCmd,
50930 clickEvent:'mousedown',
50931 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50937 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50941 cls : ' x-signature-btn x-signature-'+id,
50942 scope: editor, // was editor...
50943 handler: this.reset,
50944 clickEvent:'mousedown',
50945 text: this.labels.clear
50952 cls : ' x-signature-btn x-signature-'+id,
50953 scope: editor, // was editor...
50954 handler: this.confirmHandler,
50955 clickEvent:'mousedown',
50956 text: this.labels.confirm
50963 * when user is clicked confirm then show this image.....
50965 * @return {String} Image Data URI
50967 getImageDataURI : function(){
50968 var svg = this.svgEl.dom.parentNode.innerHTML;
50969 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50974 * @return {Boolean} this.isConfirmed
50976 getConfirmed : function(){
50977 return this.isConfirmed;
50981 * @return {Number} this.width
50983 getWidth : function(){
50988 * @return {Number} this.height
50990 getHeight : function(){
50991 return this.height;
50994 getSignature : function(){
50995 return this.signatureTmp;
50998 reset : function(){
50999 this.signatureTmp = '';
51000 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
51001 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
51002 this.isConfirmed = false;
51003 Roo.form.Signature.superclass.reset.call(this);
51005 setSignature : function(s){
51006 this.signatureTmp = s;
51007 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
51008 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
51010 this.isConfirmed = false;
51011 Roo.form.Signature.superclass.reset.call(this);
51014 // Roo.log(this.signPanel.dom.contentWindow.up())
51017 setConfirmed : function(){
51021 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
51024 confirmHandler : function(){
51025 if(!this.getSignature()){
51029 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
51030 this.setValue(this.getSignature());
51031 this.isConfirmed = true;
51033 this.fireEvent('confirm', this);
51036 // Subclasses should provide the validation implementation by overriding this
51037 validateValue : function(value){
51038 if(this.allowBlank){
51042 if(this.isConfirmed){
51049 * Ext JS Library 1.1.1
51050 * Copyright(c) 2006-2007, Ext JS, LLC.
51052 * Originally Released Under LGPL - original licence link has changed is not relivant.
51055 * <script type="text/javascript">
51060 * @class Roo.form.ComboBox
51061 * @extends Roo.form.TriggerField
51062 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
51064 * Create a new ComboBox.
51065 * @param {Object} config Configuration options
51067 Roo.form.Select = function(config){
51068 Roo.form.Select.superclass.constructor.call(this, config);
51072 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
51074 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
51077 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
51078 * rendering into an Roo.Editor, defaults to false)
51081 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
51082 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
51085 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
51088 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
51089 * the dropdown list (defaults to undefined, with no header element)
51093 * @cfg {String/Roo.Template} tpl The template to use to render the output
51097 defaultAutoCreate : {tag: "select" },
51099 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
51101 listWidth: undefined,
51103 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
51104 * mode = 'remote' or 'text' if mode = 'local')
51106 displayField: undefined,
51108 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
51109 * mode = 'remote' or 'value' if mode = 'local').
51110 * Note: use of a valueField requires the user make a selection
51111 * in order for a value to be mapped.
51113 valueField: undefined,
51117 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
51118 * field's data value (defaults to the underlying DOM element's name)
51120 hiddenName: undefined,
51122 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
51126 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
51128 selectedClass: 'x-combo-selected',
51130 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
51131 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
51132 * which displays a downward arrow icon).
51134 triggerClass : 'x-form-arrow-trigger',
51136 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
51140 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
51141 * anchor positions (defaults to 'tl-bl')
51143 listAlign: 'tl-bl?',
51145 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
51149 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
51150 * query specified by the allQuery config option (defaults to 'query')
51152 triggerAction: 'query',
51154 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
51155 * (defaults to 4, does not apply if editable = false)
51159 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
51160 * delay (typeAheadDelay) if it matches a known value (defaults to false)
51164 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
51165 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
51169 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
51170 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
51174 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
51175 * when editable = true (defaults to false)
51177 selectOnFocus:false,
51179 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
51181 queryParam: 'query',
51183 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
51184 * when mode = 'remote' (defaults to 'Loading...')
51186 loadingText: 'Loading...',
51188 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
51192 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
51196 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
51197 * traditional select (defaults to true)
51201 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
51205 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
51209 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
51210 * listWidth has a higher value)
51214 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
51215 * allow the user to set arbitrary text into the field (defaults to false)
51217 forceSelection:false,
51219 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
51220 * if typeAhead = true (defaults to 250)
51222 typeAheadDelay : 250,
51224 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
51225 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51227 valueNotFoundText : undefined,
51230 * @cfg {String} defaultValue The value displayed after loading the store.
51235 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51237 blockFocus : false,
51240 * @cfg {Boolean} disableClear Disable showing of clear button.
51242 disableClear : false,
51244 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51246 alwaysQuery : false,
51252 // element that contains real text value.. (when hidden is used..)
51255 onRender : function(ct, position){
51256 Roo.form.Field.prototype.onRender.call(this, ct, position);
51259 this.store.on('beforeload', this.onBeforeLoad, this);
51260 this.store.on('load', this.onLoad, this);
51261 this.store.on('loadexception', this.onLoadException, this);
51262 this.store.load({});
51270 initEvents : function(){
51271 //Roo.form.ComboBox.superclass.initEvents.call(this);
51275 onDestroy : function(){
51278 this.store.un('beforeload', this.onBeforeLoad, this);
51279 this.store.un('load', this.onLoad, this);
51280 this.store.un('loadexception', this.onLoadException, this);
51282 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51286 fireKey : function(e){
51287 if(e.isNavKeyPress() && !this.list.isVisible()){
51288 this.fireEvent("specialkey", this, e);
51293 onResize: function(w, h){
51301 * Allow or prevent the user from directly editing the field text. If false is passed,
51302 * the user will only be able to select from the items defined in the dropdown list. This method
51303 * is the runtime equivalent of setting the 'editable' config option at config time.
51304 * @param {Boolean} value True to allow the user to directly edit the field text
51306 setEditable : function(value){
51311 onBeforeLoad : function(){
51313 Roo.log("Select before load");
51316 this.innerList.update(this.loadingText ?
51317 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51318 //this.restrictHeight();
51319 this.selectedIndex = -1;
51323 onLoad : function(){
51326 var dom = this.el.dom;
51327 dom.innerHTML = '';
51328 var od = dom.ownerDocument;
51330 if (this.emptyText) {
51331 var op = od.createElement('option');
51332 op.setAttribute('value', '');
51333 op.innerHTML = String.format('{0}', this.emptyText);
51334 dom.appendChild(op);
51336 if(this.store.getCount() > 0){
51338 var vf = this.valueField;
51339 var df = this.displayField;
51340 this.store.data.each(function(r) {
51341 // which colmsn to use... testing - cdoe / title..
51342 var op = od.createElement('option');
51343 op.setAttribute('value', r.data[vf]);
51344 op.innerHTML = String.format('{0}', r.data[df]);
51345 dom.appendChild(op);
51347 if (typeof(this.defaultValue != 'undefined')) {
51348 this.setValue(this.defaultValue);
51353 //this.onEmptyResults();
51358 onLoadException : function()
51360 dom.innerHTML = '';
51362 Roo.log("Select on load exception");
51366 Roo.log(this.store.reader.jsonData);
51367 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51368 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51374 onTypeAhead : function(){
51379 onSelect : function(record, index){
51380 Roo.log('on select?');
51382 if(this.fireEvent('beforeselect', this, record, index) !== false){
51383 this.setFromData(index > -1 ? record.data : false);
51385 this.fireEvent('select', this, record, index);
51390 * Returns the currently selected field value or empty string if no value is set.
51391 * @return {String} value The selected value
51393 getValue : function(){
51394 var dom = this.el.dom;
51395 this.value = dom.options[dom.selectedIndex].value;
51401 * Clears any text/value currently set in the field
51403 clearValue : function(){
51405 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51410 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51411 * will be displayed in the field. If the value does not match the data value of an existing item,
51412 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51413 * Otherwise the field will be blank (although the value will still be set).
51414 * @param {String} value The value to match
51416 setValue : function(v){
51417 var d = this.el.dom;
51418 for (var i =0; i < d.options.length;i++) {
51419 if (v == d.options[i].value) {
51420 d.selectedIndex = i;
51428 * @property {Object} the last set data for the element
51433 * Sets the value of the field based on a object which is related to the record format for the store.
51434 * @param {Object} value the value to set as. or false on reset?
51436 setFromData : function(o){
51437 Roo.log('setfrom data?');
51443 reset : function(){
51447 findRecord : function(prop, value){
51452 if(this.store.getCount() > 0){
51453 this.store.each(function(r){
51454 if(r.data[prop] == value){
51464 getName: function()
51466 // returns hidden if it's set..
51467 if (!this.rendered) {return ''};
51468 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51476 onEmptyResults : function(){
51477 Roo.log('empty results');
51482 * Returns true if the dropdown list is expanded, else false.
51484 isExpanded : function(){
51489 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51490 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51491 * @param {String} value The data value of the item to select
51492 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51493 * selected item if it is not currently in view (defaults to true)
51494 * @return {Boolean} True if the value matched an item in the list, else false
51496 selectByValue : function(v, scrollIntoView){
51497 Roo.log('select By Value');
51500 if(v !== undefined && v !== null){
51501 var r = this.findRecord(this.valueField || this.displayField, v);
51503 this.select(this.store.indexOf(r), scrollIntoView);
51511 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51512 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51513 * @param {Number} index The zero-based index of the list item to select
51514 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51515 * selected item if it is not currently in view (defaults to true)
51517 select : function(index, scrollIntoView){
51518 Roo.log('select ');
51521 this.selectedIndex = index;
51522 this.view.select(index);
51523 if(scrollIntoView !== false){
51524 var el = this.view.getNode(index);
51526 this.innerList.scrollChildIntoView(el, false);
51534 validateBlur : function(){
51541 initQuery : function(){
51542 this.doQuery(this.getRawValue());
51546 doForce : function(){
51547 if(this.el.dom.value.length > 0){
51548 this.el.dom.value =
51549 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51555 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51556 * query allowing the query action to be canceled if needed.
51557 * @param {String} query The SQL query to execute
51558 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51559 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51560 * saved in the current store (defaults to false)
51562 doQuery : function(q, forceAll){
51564 Roo.log('doQuery?');
51565 if(q === undefined || q === null){
51570 forceAll: forceAll,
51574 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51578 forceAll = qe.forceAll;
51579 if(forceAll === true || (q.length >= this.minChars)){
51580 if(this.lastQuery != q || this.alwaysQuery){
51581 this.lastQuery = q;
51582 if(this.mode == 'local'){
51583 this.selectedIndex = -1;
51585 this.store.clearFilter();
51587 this.store.filter(this.displayField, q);
51591 this.store.baseParams[this.queryParam] = q;
51593 params: this.getParams(q)
51598 this.selectedIndex = -1;
51605 getParams : function(q){
51607 //p[this.queryParam] = q;
51610 p.limit = this.pageSize;
51616 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51618 collapse : function(){
51623 collapseIf : function(e){
51628 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51630 expand : function(){
51638 * @cfg {Boolean} grow
51642 * @cfg {Number} growMin
51646 * @cfg {Number} growMax
51654 setWidth : function()
51658 getResizeEl : function(){
51661 });//<script type="text/javasscript">
51665 * @class Roo.DDView
51666 * A DnD enabled version of Roo.View.
51667 * @param {Element/String} container The Element in which to create the View.
51668 * @param {String} tpl The template string used to create the markup for each element of the View
51669 * @param {Object} config The configuration properties. These include all the config options of
51670 * {@link Roo.View} plus some specific to this class.<br>
51672 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51673 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51675 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51676 .x-view-drag-insert-above {
51677 border-top:1px dotted #3366cc;
51679 .x-view-drag-insert-below {
51680 border-bottom:1px dotted #3366cc;
51686 Roo.DDView = function(container, tpl, config) {
51687 Roo.DDView.superclass.constructor.apply(this, arguments);
51688 this.getEl().setStyle("outline", "0px none");
51689 this.getEl().unselectable();
51690 if (this.dragGroup) {
51691 this.setDraggable(this.dragGroup.split(","));
51693 if (this.dropGroup) {
51694 this.setDroppable(this.dropGroup.split(","));
51696 if (this.deletable) {
51697 this.setDeletable();
51699 this.isDirtyFlag = false;
51705 Roo.extend(Roo.DDView, Roo.View, {
51706 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51707 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51708 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51709 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51713 reset: Roo.emptyFn,
51715 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51717 validate: function() {
51721 destroy: function() {
51722 this.purgeListeners();
51723 this.getEl.removeAllListeners();
51724 this.getEl().remove();
51725 if (this.dragZone) {
51726 if (this.dragZone.destroy) {
51727 this.dragZone.destroy();
51730 if (this.dropZone) {
51731 if (this.dropZone.destroy) {
51732 this.dropZone.destroy();
51737 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51738 getName: function() {
51742 /** Loads the View from a JSON string representing the Records to put into the Store. */
51743 setValue: function(v) {
51745 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51748 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51749 this.store.proxy = new Roo.data.MemoryProxy(data);
51753 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51754 getValue: function() {
51756 this.store.each(function(rec) {
51757 result += rec.id + ',';
51759 return result.substr(0, result.length - 1) + ')';
51762 getIds: function() {
51763 var i = 0, result = new Array(this.store.getCount());
51764 this.store.each(function(rec) {
51765 result[i++] = rec.id;
51770 isDirty: function() {
51771 return this.isDirtyFlag;
51775 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51776 * whole Element becomes the target, and this causes the drop gesture to append.
51778 getTargetFromEvent : function(e) {
51779 var target = e.getTarget();
51780 while ((target !== null) && (target.parentNode != this.el.dom)) {
51781 target = target.parentNode;
51784 target = this.el.dom.lastChild || this.el.dom;
51790 * Create the drag data which consists of an object which has the property "ddel" as
51791 * the drag proxy element.
51793 getDragData : function(e) {
51794 var target = this.findItemFromChild(e.getTarget());
51796 this.handleSelection(e);
51797 var selNodes = this.getSelectedNodes();
51800 copy: this.copy || (this.allowCopy && e.ctrlKey),
51804 var selectedIndices = this.getSelectedIndexes();
51805 for (var i = 0; i < selectedIndices.length; i++) {
51806 dragData.records.push(this.store.getAt(selectedIndices[i]));
51808 if (selNodes.length == 1) {
51809 dragData.ddel = target.cloneNode(true); // the div element
51811 var div = document.createElement('div'); // create the multi element drag "ghost"
51812 div.className = 'multi-proxy';
51813 for (var i = 0, len = selNodes.length; i < len; i++) {
51814 div.appendChild(selNodes[i].cloneNode(true));
51816 dragData.ddel = div;
51818 //console.log(dragData)
51819 //console.log(dragData.ddel.innerHTML)
51822 //console.log('nodragData')
51826 /** Specify to which ddGroup items in this DDView may be dragged. */
51827 setDraggable: function(ddGroup) {
51828 if (ddGroup instanceof Array) {
51829 Roo.each(ddGroup, this.setDraggable, this);
51832 if (this.dragZone) {
51833 this.dragZone.addToGroup(ddGroup);
51835 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51836 containerScroll: true,
51840 // Draggability implies selection. DragZone's mousedown selects the element.
51841 if (!this.multiSelect) { this.singleSelect = true; }
51843 // Wire the DragZone's handlers up to methods in *this*
51844 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51848 /** Specify from which ddGroup this DDView accepts drops. */
51849 setDroppable: function(ddGroup) {
51850 if (ddGroup instanceof Array) {
51851 Roo.each(ddGroup, this.setDroppable, this);
51854 if (this.dropZone) {
51855 this.dropZone.addToGroup(ddGroup);
51857 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51858 containerScroll: true,
51862 // Wire the DropZone's handlers up to methods in *this*
51863 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51864 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51865 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51866 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51867 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51871 /** Decide whether to drop above or below a View node. */
51872 getDropPoint : function(e, n, dd){
51873 if (n == this.el.dom) { return "above"; }
51874 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51875 var c = t + (b - t) / 2;
51876 var y = Roo.lib.Event.getPageY(e);
51884 onNodeEnter : function(n, dd, e, data){
51888 onNodeOver : function(n, dd, e, data){
51889 var pt = this.getDropPoint(e, n, dd);
51890 // set the insert point style on the target node
51891 var dragElClass = this.dropNotAllowed;
51894 if (pt == "above"){
51895 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51896 targetElClass = "x-view-drag-insert-above";
51898 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51899 targetElClass = "x-view-drag-insert-below";
51901 if (this.lastInsertClass != targetElClass){
51902 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51903 this.lastInsertClass = targetElClass;
51906 return dragElClass;
51909 onNodeOut : function(n, dd, e, data){
51910 this.removeDropIndicators(n);
51913 onNodeDrop : function(n, dd, e, data){
51914 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51917 var pt = this.getDropPoint(e, n, dd);
51918 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51919 if (pt == "below") { insertAt++; }
51920 for (var i = 0; i < data.records.length; i++) {
51921 var r = data.records[i];
51922 var dup = this.store.getById(r.id);
51923 if (dup && (dd != this.dragZone)) {
51924 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51927 this.store.insert(insertAt++, r.copy());
51929 data.source.isDirtyFlag = true;
51931 this.store.insert(insertAt++, r);
51933 this.isDirtyFlag = true;
51936 this.dragZone.cachedTarget = null;
51940 removeDropIndicators : function(n){
51942 Roo.fly(n).removeClass([
51943 "x-view-drag-insert-above",
51944 "x-view-drag-insert-below"]);
51945 this.lastInsertClass = "_noclass";
51950 * Utility method. Add a delete option to the DDView's context menu.
51951 * @param {String} imageUrl The URL of the "delete" icon image.
51953 setDeletable: function(imageUrl) {
51954 if (!this.singleSelect && !this.multiSelect) {
51955 this.singleSelect = true;
51957 var c = this.getContextMenu();
51958 this.contextMenu.on("itemclick", function(item) {
51961 this.remove(this.getSelectedIndexes());
51965 this.contextMenu.add({
51972 /** Return the context menu for this DDView. */
51973 getContextMenu: function() {
51974 if (!this.contextMenu) {
51975 // Create the View's context menu
51976 this.contextMenu = new Roo.menu.Menu({
51977 id: this.id + "-contextmenu"
51979 this.el.on("contextmenu", this.showContextMenu, this);
51981 return this.contextMenu;
51984 disableContextMenu: function() {
51985 if (this.contextMenu) {
51986 this.el.un("contextmenu", this.showContextMenu, this);
51990 showContextMenu: function(e, item) {
51991 item = this.findItemFromChild(e.getTarget());
51994 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51995 this.contextMenu.showAt(e.getXY());
52000 * Remove {@link Roo.data.Record}s at the specified indices.
52001 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
52003 remove: function(selectedIndices) {
52004 selectedIndices = [].concat(selectedIndices);
52005 for (var i = 0; i < selectedIndices.length; i++) {
52006 var rec = this.store.getAt(selectedIndices[i]);
52007 this.store.remove(rec);
52012 * Double click fires the event, but also, if this is draggable, and there is only one other
52013 * related DropZone, it transfers the selected node.
52015 onDblClick : function(e){
52016 var item = this.findItemFromChild(e.getTarget());
52018 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
52021 if (this.dragGroup) {
52022 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
52023 while (targets.indexOf(this.dropZone) > -1) {
52024 targets.remove(this.dropZone);
52026 if (targets.length == 1) {
52027 this.dragZone.cachedTarget = null;
52028 var el = Roo.get(targets[0].getEl());
52029 var box = el.getBox(true);
52030 targets[0].onNodeDrop(el.dom, {
52032 xy: [box.x, box.y + box.height - 1]
52033 }, null, this.getDragData(e));
52039 handleSelection: function(e) {
52040 this.dragZone.cachedTarget = null;
52041 var item = this.findItemFromChild(e.getTarget());
52043 this.clearSelections(true);
52046 if (item && (this.multiSelect || this.singleSelect)){
52047 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
52048 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
52049 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
52050 this.unselect(item);
52052 this.select(item, this.multiSelect && e.ctrlKey);
52053 this.lastSelection = item;
52058 onItemClick : function(item, index, e){
52059 if(this.fireEvent("beforeclick", this, index, item, e) === false){
52065 unselect : function(nodeInfo, suppressEvent){
52066 var node = this.getNode(nodeInfo);
52067 if(node && this.isSelected(node)){
52068 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
52069 Roo.fly(node).removeClass(this.selectedClass);
52070 this.selections.remove(node);
52071 if(!suppressEvent){
52072 this.fireEvent("selectionchange", this, this.selections);
52080 * Ext JS Library 1.1.1
52081 * Copyright(c) 2006-2007, Ext JS, LLC.
52083 * Originally Released Under LGPL - original licence link has changed is not relivant.
52086 * <script type="text/javascript">
52090 * @class Roo.LayoutManager
52091 * @extends Roo.util.Observable
52092 * Base class for layout managers.
52094 Roo.LayoutManager = function(container, config){
52095 Roo.LayoutManager.superclass.constructor.call(this);
52096 this.el = Roo.get(container);
52097 // ie scrollbar fix
52098 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
52099 document.body.scroll = "no";
52100 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
52101 this.el.position('relative');
52103 this.id = this.el.id;
52104 this.el.addClass("x-layout-container");
52105 /** false to disable window resize monitoring @type Boolean */
52106 this.monitorWindowResize = true;
52111 * Fires when a layout is performed.
52112 * @param {Roo.LayoutManager} this
52116 * @event regionresized
52117 * Fires when the user resizes a region.
52118 * @param {Roo.LayoutRegion} region The resized region
52119 * @param {Number} newSize The new size (width for east/west, height for north/south)
52121 "regionresized" : true,
52123 * @event regioncollapsed
52124 * Fires when a region is collapsed.
52125 * @param {Roo.LayoutRegion} region The collapsed region
52127 "regioncollapsed" : true,
52129 * @event regionexpanded
52130 * Fires when a region is expanded.
52131 * @param {Roo.LayoutRegion} region The expanded region
52133 "regionexpanded" : true
52135 this.updating = false;
52136 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52139 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
52141 * Returns true if this layout is currently being updated
52142 * @return {Boolean}
52144 isUpdating : function(){
52145 return this.updating;
52149 * Suspend the LayoutManager from doing auto-layouts while
52150 * making multiple add or remove calls
52152 beginUpdate : function(){
52153 this.updating = true;
52157 * Restore auto-layouts and optionally disable the manager from performing a layout
52158 * @param {Boolean} noLayout true to disable a layout update
52160 endUpdate : function(noLayout){
52161 this.updating = false;
52167 layout: function(){
52171 onRegionResized : function(region, newSize){
52172 this.fireEvent("regionresized", region, newSize);
52176 onRegionCollapsed : function(region){
52177 this.fireEvent("regioncollapsed", region);
52180 onRegionExpanded : function(region){
52181 this.fireEvent("regionexpanded", region);
52185 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
52186 * performs box-model adjustments.
52187 * @return {Object} The size as an object {width: (the width), height: (the height)}
52189 getViewSize : function(){
52191 if(this.el.dom != document.body){
52192 size = this.el.getSize();
52194 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
52196 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
52197 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
52202 * Returns the Element this layout is bound to.
52203 * @return {Roo.Element}
52205 getEl : function(){
52210 * Returns the specified region.
52211 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
52212 * @return {Roo.LayoutRegion}
52214 getRegion : function(target){
52215 return this.regions[target.toLowerCase()];
52218 onWindowResize : function(){
52219 if(this.monitorWindowResize){
52225 * Ext JS Library 1.1.1
52226 * Copyright(c) 2006-2007, Ext JS, LLC.
52228 * Originally Released Under LGPL - original licence link has changed is not relivant.
52231 * <script type="text/javascript">
52234 * @class Roo.BorderLayout
52235 * @extends Roo.LayoutManager
52236 * @children Roo.ContentPanel
52237 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52238 * please see: <br><br>
52239 * <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>
52240 * <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>
52243 var layout = new Roo.BorderLayout(document.body, {
52277 preferredTabWidth: 150
52282 var CP = Roo.ContentPanel;
52284 layout.beginUpdate();
52285 layout.add("north", new CP("north", "North"));
52286 layout.add("south", new CP("south", {title: "South", closable: true}));
52287 layout.add("west", new CP("west", {title: "West"}));
52288 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52289 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52290 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52291 layout.getRegion("center").showPanel("center1");
52292 layout.endUpdate();
52295 <b>The container the layout is rendered into can be either the body element or any other element.
52296 If it is not the body element, the container needs to either be an absolute positioned element,
52297 or you will need to add "position:relative" to the css of the container. You will also need to specify
52298 the container size if it is not the body element.</b>
52301 * Create a new BorderLayout
52302 * @param {String/HTMLElement/Element} container The container this layout is bound to
52303 * @param {Object} config Configuration options
52305 Roo.BorderLayout = function(container, config){
52306 config = config || {};
52307 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52308 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52309 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52310 var target = this.factory.validRegions[i];
52311 if(config[target]){
52312 this.addRegion(target, config[target]);
52317 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52320 * @cfg {Roo.LayoutRegion} east
52323 * @cfg {Roo.LayoutRegion} west
52326 * @cfg {Roo.LayoutRegion} north
52329 * @cfg {Roo.LayoutRegion} south
52332 * @cfg {Roo.LayoutRegion} center
52335 * Creates and adds a new region if it doesn't already exist.
52336 * @param {String} target The target region key (north, south, east, west or center).
52337 * @param {Object} config The regions config object
52338 * @return {BorderLayoutRegion} The new region
52340 addRegion : function(target, config){
52341 if(!this.regions[target]){
52342 var r = this.factory.create(target, this, config);
52343 this.bindRegion(target, r);
52345 return this.regions[target];
52349 bindRegion : function(name, r){
52350 this.regions[name] = r;
52351 r.on("visibilitychange", this.layout, this);
52352 r.on("paneladded", this.layout, this);
52353 r.on("panelremoved", this.layout, this);
52354 r.on("invalidated", this.layout, this);
52355 r.on("resized", this.onRegionResized, this);
52356 r.on("collapsed", this.onRegionCollapsed, this);
52357 r.on("expanded", this.onRegionExpanded, this);
52361 * Performs a layout update.
52363 layout : function(){
52364 if(this.updating) {
52367 var size = this.getViewSize();
52368 var w = size.width;
52369 var h = size.height;
52374 //var x = 0, y = 0;
52376 var rs = this.regions;
52377 var north = rs["north"];
52378 var south = rs["south"];
52379 var west = rs["west"];
52380 var east = rs["east"];
52381 var center = rs["center"];
52382 //if(this.hideOnLayout){ // not supported anymore
52383 //c.el.setStyle("display", "none");
52385 if(north && north.isVisible()){
52386 var b = north.getBox();
52387 var m = north.getMargins();
52388 b.width = w - (m.left+m.right);
52391 centerY = b.height + b.y + m.bottom;
52392 centerH -= centerY;
52393 north.updateBox(this.safeBox(b));
52395 if(south && south.isVisible()){
52396 var b = south.getBox();
52397 var m = south.getMargins();
52398 b.width = w - (m.left+m.right);
52400 var totalHeight = (b.height + m.top + m.bottom);
52401 b.y = h - totalHeight + m.top;
52402 centerH -= totalHeight;
52403 south.updateBox(this.safeBox(b));
52405 if(west && west.isVisible()){
52406 var b = west.getBox();
52407 var m = west.getMargins();
52408 b.height = centerH - (m.top+m.bottom);
52410 b.y = centerY + m.top;
52411 var totalWidth = (b.width + m.left + m.right);
52412 centerX += totalWidth;
52413 centerW -= totalWidth;
52414 west.updateBox(this.safeBox(b));
52416 if(east && east.isVisible()){
52417 var b = east.getBox();
52418 var m = east.getMargins();
52419 b.height = centerH - (m.top+m.bottom);
52420 var totalWidth = (b.width + m.left + m.right);
52421 b.x = w - totalWidth + m.left;
52422 b.y = centerY + m.top;
52423 centerW -= totalWidth;
52424 east.updateBox(this.safeBox(b));
52427 var m = center.getMargins();
52429 x: centerX + m.left,
52430 y: centerY + m.top,
52431 width: centerW - (m.left+m.right),
52432 height: centerH - (m.top+m.bottom)
52434 //if(this.hideOnLayout){
52435 //center.el.setStyle("display", "block");
52437 center.updateBox(this.safeBox(centerBox));
52440 this.fireEvent("layout", this);
52444 safeBox : function(box){
52445 box.width = Math.max(0, box.width);
52446 box.height = Math.max(0, box.height);
52451 * Adds a ContentPanel (or subclass) to this layout.
52452 * @param {String} target The target region key (north, south, east, west or center).
52453 * @param {Roo.ContentPanel} panel The panel to add
52454 * @return {Roo.ContentPanel} The added panel
52456 add : function(target, panel){
52458 target = target.toLowerCase();
52459 return this.regions[target].add(panel);
52463 * Remove a ContentPanel (or subclass) to this layout.
52464 * @param {String} target The target region key (north, south, east, west or center).
52465 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52466 * @return {Roo.ContentPanel} The removed panel
52468 remove : function(target, panel){
52469 target = target.toLowerCase();
52470 return this.regions[target].remove(panel);
52474 * Searches all regions for a panel with the specified id
52475 * @param {String} panelId
52476 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52478 findPanel : function(panelId){
52479 var rs = this.regions;
52480 for(var target in rs){
52481 if(typeof rs[target] != "function"){
52482 var p = rs[target].getPanel(panelId);
52492 * Searches all regions for a panel with the specified id and activates (shows) it.
52493 * @param {String/ContentPanel} panelId The panels id or the panel itself
52494 * @return {Roo.ContentPanel} The shown panel or null
52496 showPanel : function(panelId) {
52497 var rs = this.regions;
52498 for(var target in rs){
52499 var r = rs[target];
52500 if(typeof r != "function"){
52501 if(r.hasPanel(panelId)){
52502 return r.showPanel(panelId);
52510 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52511 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52513 restoreState : function(provider){
52515 provider = Roo.state.Manager;
52517 var sm = new Roo.LayoutStateManager();
52518 sm.init(this, provider);
52522 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52523 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52524 * a valid ContentPanel config object. Example:
52526 // Create the main layout
52527 var layout = new Roo.BorderLayout('main-ct', {
52538 // Create and add multiple ContentPanels at once via configs
52541 id: 'source-files',
52543 title:'Ext Source Files',
52556 * @param {Object} regions An object containing ContentPanel configs by region name
52558 batchAdd : function(regions){
52559 this.beginUpdate();
52560 for(var rname in regions){
52561 var lr = this.regions[rname];
52563 this.addTypedPanels(lr, regions[rname]);
52570 addTypedPanels : function(lr, ps){
52571 if(typeof ps == 'string'){
52572 lr.add(new Roo.ContentPanel(ps));
52574 else if(ps instanceof Array){
52575 for(var i =0, len = ps.length; i < len; i++){
52576 this.addTypedPanels(lr, ps[i]);
52579 else if(!ps.events){ // raw config?
52581 delete ps.el; // prevent conflict
52582 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52584 else { // panel object assumed!
52589 * Adds a xtype elements to the layout.
52593 xtype : 'ContentPanel',
52600 xtype : 'NestedLayoutPanel',
52606 items : [ ... list of content panels or nested layout panels.. ]
52610 * @param {Object} cfg Xtype definition of item to add.
52612 addxtype : function(cfg)
52614 // basically accepts a pannel...
52615 // can accept a layout region..!?!?
52616 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52618 if (!cfg.xtype.match(/Panel$/)) {
52623 if (typeof(cfg.region) == 'undefined') {
52624 Roo.log("Failed to add Panel, region was not set");
52628 var region = cfg.region;
52634 xitems = cfg.items;
52641 case 'ContentPanel': // ContentPanel (el, cfg)
52642 case 'ScrollPanel': // ContentPanel (el, cfg)
52644 if(cfg.autoCreate) {
52645 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52647 var el = this.el.createChild();
52648 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52651 this.add(region, ret);
52655 case 'TreePanel': // our new panel!
52656 cfg.el = this.el.createChild();
52657 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52658 this.add(region, ret);
52661 case 'NestedLayoutPanel':
52662 // create a new Layout (which is a Border Layout...
52663 var el = this.el.createChild();
52664 var clayout = cfg.layout;
52666 clayout.items = clayout.items || [];
52667 // replace this exitems with the clayout ones..
52668 xitems = clayout.items;
52671 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52672 cfg.background = false;
52674 var layout = new Roo.BorderLayout(el, clayout);
52676 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52677 //console.log('adding nested layout panel ' + cfg.toSource());
52678 this.add(region, ret);
52679 nb = {}; /// find first...
52684 // needs grid and region
52686 //var el = this.getRegion(region).el.createChild();
52687 var el = this.el.createChild();
52688 // create the grid first...
52690 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52692 if (region == 'center' && this.active ) {
52693 cfg.background = false;
52695 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52697 this.add(region, ret);
52698 if (cfg.background) {
52699 ret.on('activate', function(gp) {
52700 if (!gp.grid.rendered) {
52715 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52717 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52718 this.add(region, ret);
52721 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52725 // GridPanel (grid, cfg)
52728 this.beginUpdate();
52732 Roo.each(xitems, function(i) {
52733 region = nb && i.region ? i.region : false;
52735 var add = ret.addxtype(i);
52738 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52739 if (!i.background) {
52740 abn[region] = nb[region] ;
52747 // make the last non-background panel active..
52748 //if (nb) { Roo.log(abn); }
52751 for(var r in abn) {
52752 region = this.getRegion(r);
52754 // tried using nb[r], but it does not work..
52756 region.showPanel(abn[r]);
52767 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52768 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52769 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52770 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52773 var CP = Roo.ContentPanel;
52775 var layout = Roo.BorderLayout.create({
52779 panels: [new CP("north", "North")]
52788 panels: [new CP("west", {title: "West"})]
52797 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52806 panels: [new CP("south", {title: "South", closable: true})]
52813 preferredTabWidth: 150,
52815 new CP("center1", {title: "Close Me", closable: true}),
52816 new CP("center2", {title: "Center Panel", closable: false})
52821 layout.getRegion("center").showPanel("center1");
52826 Roo.BorderLayout.create = function(config, targetEl){
52827 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52828 layout.beginUpdate();
52829 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52830 for(var j = 0, jlen = regions.length; j < jlen; j++){
52831 var lr = regions[j];
52832 if(layout.regions[lr] && config[lr].panels){
52833 var r = layout.regions[lr];
52834 var ps = config[lr].panels;
52835 layout.addTypedPanels(r, ps);
52838 layout.endUpdate();
52843 Roo.BorderLayout.RegionFactory = {
52845 validRegions : ["north","south","east","west","center"],
52848 create : function(target, mgr, config){
52849 target = target.toLowerCase();
52850 if(config.lightweight || config.basic){
52851 return new Roo.BasicLayoutRegion(mgr, config, target);
52855 return new Roo.NorthLayoutRegion(mgr, config);
52857 return new Roo.SouthLayoutRegion(mgr, config);
52859 return new Roo.EastLayoutRegion(mgr, config);
52861 return new Roo.WestLayoutRegion(mgr, config);
52863 return new Roo.CenterLayoutRegion(mgr, config);
52865 throw 'Layout region "'+target+'" not supported.';
52869 * Ext JS Library 1.1.1
52870 * Copyright(c) 2006-2007, Ext JS, LLC.
52872 * Originally Released Under LGPL - original licence link has changed is not relivant.
52875 * <script type="text/javascript">
52879 * @class Roo.BasicLayoutRegion
52880 * @extends Roo.util.Observable
52881 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52882 * and does not have a titlebar, tabs or any other features. All it does is size and position
52883 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52885 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52887 this.position = pos;
52890 * @scope Roo.BasicLayoutRegion
52894 * @event beforeremove
52895 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52896 * @param {Roo.LayoutRegion} this
52897 * @param {Roo.ContentPanel} panel The panel
52898 * @param {Object} e The cancel event object
52900 "beforeremove" : true,
52902 * @event invalidated
52903 * Fires when the layout for this region is changed.
52904 * @param {Roo.LayoutRegion} this
52906 "invalidated" : true,
52908 * @event visibilitychange
52909 * Fires when this region is shown or hidden
52910 * @param {Roo.LayoutRegion} this
52911 * @param {Boolean} visibility true or false
52913 "visibilitychange" : true,
52915 * @event paneladded
52916 * Fires when a panel is added.
52917 * @param {Roo.LayoutRegion} this
52918 * @param {Roo.ContentPanel} panel The panel
52920 "paneladded" : true,
52922 * @event panelremoved
52923 * Fires when a panel is removed.
52924 * @param {Roo.LayoutRegion} this
52925 * @param {Roo.ContentPanel} panel The panel
52927 "panelremoved" : true,
52929 * @event beforecollapse
52930 * Fires when this region before collapse.
52931 * @param {Roo.LayoutRegion} this
52933 "beforecollapse" : true,
52936 * Fires when this region is collapsed.
52937 * @param {Roo.LayoutRegion} this
52939 "collapsed" : true,
52942 * Fires when this region is expanded.
52943 * @param {Roo.LayoutRegion} this
52948 * Fires when this region is slid into view.
52949 * @param {Roo.LayoutRegion} this
52951 "slideshow" : true,
52954 * Fires when this region slides out of view.
52955 * @param {Roo.LayoutRegion} this
52957 "slidehide" : true,
52959 * @event panelactivated
52960 * Fires when a panel is activated.
52961 * @param {Roo.LayoutRegion} this
52962 * @param {Roo.ContentPanel} panel The activated panel
52964 "panelactivated" : true,
52967 * Fires when the user resizes this region.
52968 * @param {Roo.LayoutRegion} this
52969 * @param {Number} newSize The new size (width for east/west, height for north/south)
52973 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52974 this.panels = new Roo.util.MixedCollection();
52975 this.panels.getKey = this.getPanelId.createDelegate(this);
52977 this.activePanel = null;
52978 // ensure listeners are added...
52980 if (config.listeners || config.events) {
52981 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52982 listeners : config.listeners || {},
52983 events : config.events || {}
52987 if(skipConfig !== true){
52988 this.applyConfig(config);
52992 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52993 getPanelId : function(p){
52997 applyConfig : function(config){
52998 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52999 this.config = config;
53004 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
53005 * the width, for horizontal (north, south) the height.
53006 * @param {Number} newSize The new width or height
53008 resizeTo : function(newSize){
53009 var el = this.el ? this.el :
53010 (this.activePanel ? this.activePanel.getEl() : null);
53012 switch(this.position){
53015 el.setWidth(newSize);
53016 this.fireEvent("resized", this, newSize);
53020 el.setHeight(newSize);
53021 this.fireEvent("resized", this, newSize);
53027 getBox : function(){
53028 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
53031 getMargins : function(){
53032 return this.margins;
53035 updateBox : function(box){
53037 var el = this.activePanel.getEl();
53038 el.dom.style.left = box.x + "px";
53039 el.dom.style.top = box.y + "px";
53040 this.activePanel.setSize(box.width, box.height);
53044 * Returns the container element for this region.
53045 * @return {Roo.Element}
53047 getEl : function(){
53048 return this.activePanel;
53052 * Returns true if this region is currently visible.
53053 * @return {Boolean}
53055 isVisible : function(){
53056 return this.activePanel ? true : false;
53059 setActivePanel : function(panel){
53060 panel = this.getPanel(panel);
53061 if(this.activePanel && this.activePanel != panel){
53062 this.activePanel.setActiveState(false);
53063 this.activePanel.getEl().setLeftTop(-10000,-10000);
53065 this.activePanel = panel;
53066 panel.setActiveState(true);
53068 panel.setSize(this.box.width, this.box.height);
53070 this.fireEvent("panelactivated", this, panel);
53071 this.fireEvent("invalidated");
53075 * Show the specified panel.
53076 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
53077 * @return {Roo.ContentPanel} The shown panel or null
53079 showPanel : function(panel){
53080 if(panel = this.getPanel(panel)){
53081 this.setActivePanel(panel);
53087 * Get the active panel for this region.
53088 * @return {Roo.ContentPanel} The active panel or null
53090 getActivePanel : function(){
53091 return this.activePanel;
53095 * Add the passed ContentPanel(s)
53096 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53097 * @return {Roo.ContentPanel} The panel added (if only one was added)
53099 add : function(panel){
53100 if(arguments.length > 1){
53101 for(var i = 0, len = arguments.length; i < len; i++) {
53102 this.add(arguments[i]);
53106 if(this.hasPanel(panel)){
53107 this.showPanel(panel);
53110 var el = panel.getEl();
53111 if(el.dom.parentNode != this.mgr.el.dom){
53112 this.mgr.el.dom.appendChild(el.dom);
53114 if(panel.setRegion){
53115 panel.setRegion(this);
53117 this.panels.add(panel);
53118 el.setStyle("position", "absolute");
53119 if(!panel.background){
53120 this.setActivePanel(panel);
53121 if(this.config.initialSize && this.panels.getCount()==1){
53122 this.resizeTo(this.config.initialSize);
53125 this.fireEvent("paneladded", this, panel);
53130 * Returns true if the panel is in this region.
53131 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53132 * @return {Boolean}
53134 hasPanel : function(panel){
53135 if(typeof panel == "object"){ // must be panel obj
53136 panel = panel.getId();
53138 return this.getPanel(panel) ? true : false;
53142 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53143 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53144 * @param {Boolean} preservePanel Overrides the config preservePanel option
53145 * @return {Roo.ContentPanel} The panel that was removed
53147 remove : function(panel, preservePanel){
53148 panel = this.getPanel(panel);
53153 this.fireEvent("beforeremove", this, panel, e);
53154 if(e.cancel === true){
53157 var panelId = panel.getId();
53158 this.panels.removeKey(panelId);
53163 * Returns the panel specified or null if it's not in this region.
53164 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53165 * @return {Roo.ContentPanel}
53167 getPanel : function(id){
53168 if(typeof id == "object"){ // must be panel obj
53171 return this.panels.get(id);
53175 * Returns this regions position (north/south/east/west/center).
53178 getPosition: function(){
53179 return this.position;
53183 * Ext JS Library 1.1.1
53184 * Copyright(c) 2006-2007, Ext JS, LLC.
53186 * Originally Released Under LGPL - original licence link has changed is not relivant.
53189 * <script type="text/javascript">
53193 * @class Roo.LayoutRegion
53194 * @extends Roo.BasicLayoutRegion
53195 * This class represents a region in a layout manager.
53196 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
53197 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
53198 * @cfg {Boolean} floatable False to disable floating (defaults to true)
53199 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
53200 * @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})
53201 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
53202 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
53203 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
53204 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
53205 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
53206 * @cfg {String} title The title for the region (overrides panel titles)
53207 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
53208 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
53209 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
53210 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
53211 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
53212 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
53213 * the space available, similar to FireFox 1.5 tabs (defaults to false)
53214 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
53215 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
53216 * @cfg {Boolean} showPin True to show a pin button
53217 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
53218 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
53219 * @cfg {Boolean} disableTabTips True to disable tab tooltips
53220 * @cfg {Number} width For East/West panels
53221 * @cfg {Number} height For North/South panels
53222 * @cfg {Boolean} split To show the splitter
53223 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
53225 Roo.LayoutRegion = function(mgr, config, pos){
53226 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
53227 var dh = Roo.DomHelper;
53228 /** This region's container element
53229 * @type Roo.Element */
53230 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
53231 /** This region's title element
53232 * @type Roo.Element */
53234 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
53235 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
53236 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
53238 this.titleEl.enableDisplayMode();
53239 /** This region's title text element
53240 * @type HTMLElement */
53241 this.titleTextEl = this.titleEl.dom.firstChild;
53242 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53243 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53244 this.closeBtn.enableDisplayMode();
53245 this.closeBtn.on("click", this.closeClicked, this);
53246 this.closeBtn.hide();
53248 this.createBody(config);
53249 this.visible = true;
53250 this.collapsed = false;
53252 if(config.hideWhenEmpty){
53254 this.on("paneladded", this.validateVisibility, this);
53255 this.on("panelremoved", this.validateVisibility, this);
53257 this.applyConfig(config);
53260 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53262 createBody : function(){
53263 /** This region's body element
53264 * @type Roo.Element */
53265 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53268 applyConfig : function(c){
53269 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53270 var dh = Roo.DomHelper;
53271 if(c.titlebar !== false){
53272 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53273 this.collapseBtn.on("click", this.collapse, this);
53274 this.collapseBtn.enableDisplayMode();
53276 if(c.showPin === true || this.showPin){
53277 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53278 this.stickBtn.enableDisplayMode();
53279 this.stickBtn.on("click", this.expand, this);
53280 this.stickBtn.hide();
53283 /** This region's collapsed element
53284 * @type Roo.Element */
53285 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53286 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53288 if(c.floatable !== false){
53289 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53290 this.collapsedEl.on("click", this.collapseClick, this);
53293 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53294 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53295 id: "message", unselectable: "on", style:{"float":"left"}});
53296 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53298 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53299 this.expandBtn.on("click", this.expand, this);
53301 if(this.collapseBtn){
53302 this.collapseBtn.setVisible(c.collapsible == true);
53304 this.cmargins = c.cmargins || this.cmargins ||
53305 (this.position == "west" || this.position == "east" ?
53306 {top: 0, left: 2, right:2, bottom: 0} :
53307 {top: 2, left: 0, right:0, bottom: 2});
53308 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53309 this.bottomTabs = c.tabPosition != "top";
53310 this.autoScroll = c.autoScroll || false;
53311 if(this.autoScroll){
53312 this.bodyEl.setStyle("overflow", "auto");
53314 this.bodyEl.setStyle("overflow", "hidden");
53316 //if(c.titlebar !== false){
53317 if((!c.titlebar && !c.title) || c.titlebar === false){
53318 this.titleEl.hide();
53320 this.titleEl.show();
53322 this.titleTextEl.innerHTML = c.title;
53326 this.duration = c.duration || .30;
53327 this.slideDuration = c.slideDuration || .45;
53330 this.collapse(true);
53337 * Returns true if this region is currently visible.
53338 * @return {Boolean}
53340 isVisible : function(){
53341 return this.visible;
53345 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53346 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53348 setCollapsedTitle : function(title){
53349 title = title || " ";
53350 if(this.collapsedTitleTextEl){
53351 this.collapsedTitleTextEl.innerHTML = title;
53355 getBox : function(){
53357 if(!this.collapsed){
53358 b = this.el.getBox(false, true);
53360 b = this.collapsedEl.getBox(false, true);
53365 getMargins : function(){
53366 return this.collapsed ? this.cmargins : this.margins;
53369 highlight : function(){
53370 this.el.addClass("x-layout-panel-dragover");
53373 unhighlight : function(){
53374 this.el.removeClass("x-layout-panel-dragover");
53377 updateBox : function(box){
53379 if(!this.collapsed){
53380 this.el.dom.style.left = box.x + "px";
53381 this.el.dom.style.top = box.y + "px";
53382 this.updateBody(box.width, box.height);
53384 this.collapsedEl.dom.style.left = box.x + "px";
53385 this.collapsedEl.dom.style.top = box.y + "px";
53386 this.collapsedEl.setSize(box.width, box.height);
53389 this.tabs.autoSizeTabs();
53393 updateBody : function(w, h){
53395 this.el.setWidth(w);
53396 w -= this.el.getBorderWidth("rl");
53397 if(this.config.adjustments){
53398 w += this.config.adjustments[0];
53402 this.el.setHeight(h);
53403 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53404 h -= this.el.getBorderWidth("tb");
53405 if(this.config.adjustments){
53406 h += this.config.adjustments[1];
53408 this.bodyEl.setHeight(h);
53410 h = this.tabs.syncHeight(h);
53413 if(this.panelSize){
53414 w = w !== null ? w : this.panelSize.width;
53415 h = h !== null ? h : this.panelSize.height;
53417 if(this.activePanel){
53418 var el = this.activePanel.getEl();
53419 w = w !== null ? w : el.getWidth();
53420 h = h !== null ? h : el.getHeight();
53421 this.panelSize = {width: w, height: h};
53422 this.activePanel.setSize(w, h);
53424 if(Roo.isIE && this.tabs){
53425 this.tabs.el.repaint();
53430 * Returns the container element for this region.
53431 * @return {Roo.Element}
53433 getEl : function(){
53438 * Hides this region.
53441 if(!this.collapsed){
53442 this.el.dom.style.left = "-2000px";
53445 this.collapsedEl.dom.style.left = "-2000px";
53446 this.collapsedEl.hide();
53448 this.visible = false;
53449 this.fireEvent("visibilitychange", this, false);
53453 * Shows this region if it was previously hidden.
53456 if(!this.collapsed){
53459 this.collapsedEl.show();
53461 this.visible = true;
53462 this.fireEvent("visibilitychange", this, true);
53465 closeClicked : function(){
53466 if(this.activePanel){
53467 this.remove(this.activePanel);
53471 collapseClick : function(e){
53473 e.stopPropagation();
53476 e.stopPropagation();
53482 * Collapses this region.
53483 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53485 collapse : function(skipAnim, skipCheck){
53486 if(this.collapsed) {
53490 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53492 this.collapsed = true;
53494 this.split.el.hide();
53496 if(this.config.animate && skipAnim !== true){
53497 this.fireEvent("invalidated", this);
53498 this.animateCollapse();
53500 this.el.setLocation(-20000,-20000);
53502 this.collapsedEl.show();
53503 this.fireEvent("collapsed", this);
53504 this.fireEvent("invalidated", this);
53510 animateCollapse : function(){
53515 * Expands this region if it was previously collapsed.
53516 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53517 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53519 expand : function(e, skipAnim){
53521 e.stopPropagation();
53523 if(!this.collapsed || this.el.hasActiveFx()) {
53527 this.afterSlideIn();
53530 this.collapsed = false;
53531 if(this.config.animate && skipAnim !== true){
53532 this.animateExpand();
53536 this.split.el.show();
53538 this.collapsedEl.setLocation(-2000,-2000);
53539 this.collapsedEl.hide();
53540 this.fireEvent("invalidated", this);
53541 this.fireEvent("expanded", this);
53545 animateExpand : function(){
53549 initTabs : function()
53551 this.bodyEl.setStyle("overflow", "hidden");
53552 var ts = new Roo.TabPanel(
53555 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53556 disableTooltips: this.config.disableTabTips,
53557 toolbar : this.config.toolbar
53560 if(this.config.hideTabs){
53561 ts.stripWrap.setDisplayed(false);
53564 ts.resizeTabs = this.config.resizeTabs === true;
53565 ts.minTabWidth = this.config.minTabWidth || 40;
53566 ts.maxTabWidth = this.config.maxTabWidth || 250;
53567 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53568 ts.monitorResize = false;
53569 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53570 ts.bodyEl.addClass('x-layout-tabs-body');
53571 this.panels.each(this.initPanelAsTab, this);
53574 initPanelAsTab : function(panel){
53575 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53576 this.config.closeOnTab && panel.isClosable());
53577 if(panel.tabTip !== undefined){
53578 ti.setTooltip(panel.tabTip);
53580 ti.on("activate", function(){
53581 this.setActivePanel(panel);
53583 if(this.config.closeOnTab){
53584 ti.on("beforeclose", function(t, e){
53586 this.remove(panel);
53592 updatePanelTitle : function(panel, title){
53593 if(this.activePanel == panel){
53594 this.updateTitle(title);
53597 var ti = this.tabs.getTab(panel.getEl().id);
53599 if(panel.tabTip !== undefined){
53600 ti.setTooltip(panel.tabTip);
53605 updateTitle : function(title){
53606 if(this.titleTextEl && !this.config.title){
53607 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53611 setActivePanel : function(panel){
53612 panel = this.getPanel(panel);
53613 if(this.activePanel && this.activePanel != panel){
53614 this.activePanel.setActiveState(false);
53616 this.activePanel = panel;
53617 panel.setActiveState(true);
53618 if(this.panelSize){
53619 panel.setSize(this.panelSize.width, this.panelSize.height);
53622 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53624 this.updateTitle(panel.getTitle());
53626 this.fireEvent("invalidated", this);
53628 this.fireEvent("panelactivated", this, panel);
53632 * Shows the specified panel.
53633 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53634 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53636 showPanel : function(panel)
53638 panel = this.getPanel(panel);
53641 var tab = this.tabs.getTab(panel.getEl().id);
53642 if(tab.isHidden()){
53643 this.tabs.unhideTab(tab.id);
53647 this.setActivePanel(panel);
53654 * Get the active panel for this region.
53655 * @return {Roo.ContentPanel} The active panel or null
53657 getActivePanel : function(){
53658 return this.activePanel;
53661 validateVisibility : function(){
53662 if(this.panels.getCount() < 1){
53663 this.updateTitle(" ");
53664 this.closeBtn.hide();
53667 if(!this.isVisible()){
53674 * Adds the passed ContentPanel(s) to this region.
53675 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53676 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53678 add : function(panel){
53679 if(arguments.length > 1){
53680 for(var i = 0, len = arguments.length; i < len; i++) {
53681 this.add(arguments[i]);
53685 if(this.hasPanel(panel)){
53686 this.showPanel(panel);
53689 panel.setRegion(this);
53690 this.panels.add(panel);
53691 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53692 this.bodyEl.dom.appendChild(panel.getEl().dom);
53693 if(panel.background !== true){
53694 this.setActivePanel(panel);
53696 this.fireEvent("paneladded", this, panel);
53702 this.initPanelAsTab(panel);
53704 if(panel.background !== true){
53705 this.tabs.activate(panel.getEl().id);
53707 this.fireEvent("paneladded", this, panel);
53712 * Hides the tab for the specified panel.
53713 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53715 hidePanel : function(panel){
53716 if(this.tabs && (panel = this.getPanel(panel))){
53717 this.tabs.hideTab(panel.getEl().id);
53722 * Unhides the tab for a previously hidden panel.
53723 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53725 unhidePanel : function(panel){
53726 if(this.tabs && (panel = this.getPanel(panel))){
53727 this.tabs.unhideTab(panel.getEl().id);
53731 clearPanels : function(){
53732 while(this.panels.getCount() > 0){
53733 this.remove(this.panels.first());
53738 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53739 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53740 * @param {Boolean} preservePanel Overrides the config preservePanel option
53741 * @return {Roo.ContentPanel} The panel that was removed
53743 remove : function(panel, preservePanel){
53744 panel = this.getPanel(panel);
53749 this.fireEvent("beforeremove", this, panel, e);
53750 if(e.cancel === true){
53753 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53754 var panelId = panel.getId();
53755 this.panels.removeKey(panelId);
53757 document.body.appendChild(panel.getEl().dom);
53760 this.tabs.removeTab(panel.getEl().id);
53761 }else if (!preservePanel){
53762 this.bodyEl.dom.removeChild(panel.getEl().dom);
53764 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53765 var p = this.panels.first();
53766 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53767 tempEl.appendChild(p.getEl().dom);
53768 this.bodyEl.update("");
53769 this.bodyEl.dom.appendChild(p.getEl().dom);
53771 this.updateTitle(p.getTitle());
53773 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53774 this.setActivePanel(p);
53776 panel.setRegion(null);
53777 if(this.activePanel == panel){
53778 this.activePanel = null;
53780 if(this.config.autoDestroy !== false && preservePanel !== true){
53781 try{panel.destroy();}catch(e){}
53783 this.fireEvent("panelremoved", this, panel);
53788 * Returns the TabPanel component used by this region
53789 * @return {Roo.TabPanel}
53791 getTabs : function(){
53795 createTool : function(parentEl, className){
53796 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53797 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53798 btn.addClassOnOver("x-layout-tools-button-over");
53803 * Ext JS Library 1.1.1
53804 * Copyright(c) 2006-2007, Ext JS, LLC.
53806 * Originally Released Under LGPL - original licence link has changed is not relivant.
53809 * <script type="text/javascript">
53815 * @class Roo.SplitLayoutRegion
53816 * @extends Roo.LayoutRegion
53817 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53819 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53820 this.cursor = cursor;
53821 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53824 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53825 splitTip : "Drag to resize.",
53826 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53827 useSplitTips : false,
53829 applyConfig : function(config){
53830 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53833 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53834 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53835 /** The SplitBar for this region
53836 * @type Roo.SplitBar */
53837 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53838 this.split.on("moved", this.onSplitMove, this);
53839 this.split.useShim = config.useShim === true;
53840 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53841 if(this.useSplitTips){
53842 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53844 if(config.collapsible){
53845 this.split.el.on("dblclick", this.collapse, this);
53848 if(typeof config.minSize != "undefined"){
53849 this.split.minSize = config.minSize;
53851 if(typeof config.maxSize != "undefined"){
53852 this.split.maxSize = config.maxSize;
53854 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53855 this.hideSplitter();
53860 getHMaxSize : function(){
53861 var cmax = this.config.maxSize || 10000;
53862 var center = this.mgr.getRegion("center");
53863 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53866 getVMaxSize : function(){
53867 var cmax = this.config.maxSize || 10000;
53868 var center = this.mgr.getRegion("center");
53869 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53872 onSplitMove : function(split, newSize){
53873 this.fireEvent("resized", this, newSize);
53877 * Returns the {@link Roo.SplitBar} for this region.
53878 * @return {Roo.SplitBar}
53880 getSplitBar : function(){
53885 this.hideSplitter();
53886 Roo.SplitLayoutRegion.superclass.hide.call(this);
53889 hideSplitter : function(){
53891 this.split.el.setLocation(-2000,-2000);
53892 this.split.el.hide();
53898 this.split.el.show();
53900 Roo.SplitLayoutRegion.superclass.show.call(this);
53903 beforeSlide: function(){
53904 if(Roo.isGecko){// firefox overflow auto bug workaround
53905 this.bodyEl.clip();
53907 this.tabs.bodyEl.clip();
53909 if(this.activePanel){
53910 this.activePanel.getEl().clip();
53912 if(this.activePanel.beforeSlide){
53913 this.activePanel.beforeSlide();
53919 afterSlide : function(){
53920 if(Roo.isGecko){// firefox overflow auto bug workaround
53921 this.bodyEl.unclip();
53923 this.tabs.bodyEl.unclip();
53925 if(this.activePanel){
53926 this.activePanel.getEl().unclip();
53927 if(this.activePanel.afterSlide){
53928 this.activePanel.afterSlide();
53934 initAutoHide : function(){
53935 if(this.autoHide !== false){
53936 if(!this.autoHideHd){
53937 var st = new Roo.util.DelayedTask(this.slideIn, this);
53938 this.autoHideHd = {
53939 "mouseout": function(e){
53940 if(!e.within(this.el, true)){
53944 "mouseover" : function(e){
53950 this.el.on(this.autoHideHd);
53954 clearAutoHide : function(){
53955 if(this.autoHide !== false){
53956 this.el.un("mouseout", this.autoHideHd.mouseout);
53957 this.el.un("mouseover", this.autoHideHd.mouseover);
53961 clearMonitor : function(){
53962 Roo.get(document).un("click", this.slideInIf, this);
53965 // these names are backwards but not changed for compat
53966 slideOut : function(){
53967 if(this.isSlid || this.el.hasActiveFx()){
53970 this.isSlid = true;
53971 if(this.collapseBtn){
53972 this.collapseBtn.hide();
53974 this.closeBtnState = this.closeBtn.getStyle('display');
53975 this.closeBtn.hide();
53977 this.stickBtn.show();
53980 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53981 this.beforeSlide();
53982 this.el.setStyle("z-index", 10001);
53983 this.el.slideIn(this.getSlideAnchor(), {
53984 callback: function(){
53986 this.initAutoHide();
53987 Roo.get(document).on("click", this.slideInIf, this);
53988 this.fireEvent("slideshow", this);
53995 afterSlideIn : function(){
53996 this.clearAutoHide();
53997 this.isSlid = false;
53998 this.clearMonitor();
53999 this.el.setStyle("z-index", "");
54000 if(this.collapseBtn){
54001 this.collapseBtn.show();
54003 this.closeBtn.setStyle('display', this.closeBtnState);
54005 this.stickBtn.hide();
54007 this.fireEvent("slidehide", this);
54010 slideIn : function(cb){
54011 if(!this.isSlid || this.el.hasActiveFx()){
54015 this.isSlid = false;
54016 this.beforeSlide();
54017 this.el.slideOut(this.getSlideAnchor(), {
54018 callback: function(){
54019 this.el.setLeftTop(-10000, -10000);
54021 this.afterSlideIn();
54029 slideInIf : function(e){
54030 if(!e.within(this.el)){
54035 animateCollapse : function(){
54036 this.beforeSlide();
54037 this.el.setStyle("z-index", 20000);
54038 var anchor = this.getSlideAnchor();
54039 this.el.slideOut(anchor, {
54040 callback : function(){
54041 this.el.setStyle("z-index", "");
54042 this.collapsedEl.slideIn(anchor, {duration:.3});
54044 this.el.setLocation(-10000,-10000);
54046 this.fireEvent("collapsed", this);
54053 animateExpand : function(){
54054 this.beforeSlide();
54055 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
54056 this.el.setStyle("z-index", 20000);
54057 this.collapsedEl.hide({
54060 this.el.slideIn(this.getSlideAnchor(), {
54061 callback : function(){
54062 this.el.setStyle("z-index", "");
54065 this.split.el.show();
54067 this.fireEvent("invalidated", this);
54068 this.fireEvent("expanded", this);
54096 getAnchor : function(){
54097 return this.anchors[this.position];
54100 getCollapseAnchor : function(){
54101 return this.canchors[this.position];
54104 getSlideAnchor : function(){
54105 return this.sanchors[this.position];
54108 getAlignAdj : function(){
54109 var cm = this.cmargins;
54110 switch(this.position){
54126 getExpandAdj : function(){
54127 var c = this.collapsedEl, cm = this.cmargins;
54128 switch(this.position){
54130 return [-(cm.right+c.getWidth()+cm.left), 0];
54133 return [cm.right+c.getWidth()+cm.left, 0];
54136 return [0, -(cm.top+cm.bottom+c.getHeight())];
54139 return [0, cm.top+cm.bottom+c.getHeight()];
54145 * Ext JS Library 1.1.1
54146 * Copyright(c) 2006-2007, Ext JS, LLC.
54148 * Originally Released Under LGPL - original licence link has changed is not relivant.
54151 * <script type="text/javascript">
54154 * These classes are private internal classes
54156 Roo.CenterLayoutRegion = function(mgr, config){
54157 Roo.LayoutRegion.call(this, mgr, config, "center");
54158 this.visible = true;
54159 this.minWidth = config.minWidth || 20;
54160 this.minHeight = config.minHeight || 20;
54163 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
54165 // center panel can't be hidden
54169 // center panel can't be hidden
54172 getMinWidth: function(){
54173 return this.minWidth;
54176 getMinHeight: function(){
54177 return this.minHeight;
54182 Roo.NorthLayoutRegion = function(mgr, config){
54183 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
54185 this.split.placement = Roo.SplitBar.TOP;
54186 this.split.orientation = Roo.SplitBar.VERTICAL;
54187 this.split.el.addClass("x-layout-split-v");
54189 var size = config.initialSize || config.height;
54190 if(typeof size != "undefined"){
54191 this.el.setHeight(size);
54194 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
54195 orientation: Roo.SplitBar.VERTICAL,
54196 getBox : function(){
54197 if(this.collapsed){
54198 return this.collapsedEl.getBox();
54200 var box = this.el.getBox();
54202 box.height += this.split.el.getHeight();
54207 updateBox : function(box){
54208 if(this.split && !this.collapsed){
54209 box.height -= this.split.el.getHeight();
54210 this.split.el.setLeft(box.x);
54211 this.split.el.setTop(box.y+box.height);
54212 this.split.el.setWidth(box.width);
54214 if(this.collapsed){
54215 this.updateBody(box.width, null);
54217 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54221 Roo.SouthLayoutRegion = function(mgr, config){
54222 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
54224 this.split.placement = Roo.SplitBar.BOTTOM;
54225 this.split.orientation = Roo.SplitBar.VERTICAL;
54226 this.split.el.addClass("x-layout-split-v");
54228 var size = config.initialSize || config.height;
54229 if(typeof size != "undefined"){
54230 this.el.setHeight(size);
54233 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
54234 orientation: Roo.SplitBar.VERTICAL,
54235 getBox : function(){
54236 if(this.collapsed){
54237 return this.collapsedEl.getBox();
54239 var box = this.el.getBox();
54241 var sh = this.split.el.getHeight();
54248 updateBox : function(box){
54249 if(this.split && !this.collapsed){
54250 var sh = this.split.el.getHeight();
54253 this.split.el.setLeft(box.x);
54254 this.split.el.setTop(box.y-sh);
54255 this.split.el.setWidth(box.width);
54257 if(this.collapsed){
54258 this.updateBody(box.width, null);
54260 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54264 Roo.EastLayoutRegion = function(mgr, config){
54265 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54267 this.split.placement = Roo.SplitBar.RIGHT;
54268 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54269 this.split.el.addClass("x-layout-split-h");
54271 var size = config.initialSize || config.width;
54272 if(typeof size != "undefined"){
54273 this.el.setWidth(size);
54276 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54277 orientation: Roo.SplitBar.HORIZONTAL,
54278 getBox : function(){
54279 if(this.collapsed){
54280 return this.collapsedEl.getBox();
54282 var box = this.el.getBox();
54284 var sw = this.split.el.getWidth();
54291 updateBox : function(box){
54292 if(this.split && !this.collapsed){
54293 var sw = this.split.el.getWidth();
54295 this.split.el.setLeft(box.x);
54296 this.split.el.setTop(box.y);
54297 this.split.el.setHeight(box.height);
54300 if(this.collapsed){
54301 this.updateBody(null, box.height);
54303 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54307 Roo.WestLayoutRegion = function(mgr, config){
54308 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54310 this.split.placement = Roo.SplitBar.LEFT;
54311 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54312 this.split.el.addClass("x-layout-split-h");
54314 var size = config.initialSize || config.width;
54315 if(typeof size != "undefined"){
54316 this.el.setWidth(size);
54319 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
54320 orientation: Roo.SplitBar.HORIZONTAL,
54321 getBox : function(){
54322 if(this.collapsed){
54323 return this.collapsedEl.getBox();
54325 var box = this.el.getBox();
54327 box.width += this.split.el.getWidth();
54332 updateBox : function(box){
54333 if(this.split && !this.collapsed){
54334 var sw = this.split.el.getWidth();
54336 this.split.el.setLeft(box.x+box.width);
54337 this.split.el.setTop(box.y);
54338 this.split.el.setHeight(box.height);
54340 if(this.collapsed){
54341 this.updateBody(null, box.height);
54343 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54348 * Ext JS Library 1.1.1
54349 * Copyright(c) 2006-2007, Ext JS, LLC.
54351 * Originally Released Under LGPL - original licence link has changed is not relivant.
54354 * <script type="text/javascript">
54359 * Private internal class for reading and applying state
54361 Roo.LayoutStateManager = function(layout){
54362 // default empty state
54371 Roo.LayoutStateManager.prototype = {
54372 init : function(layout, provider){
54373 this.provider = provider;
54374 var state = provider.get(layout.id+"-layout-state");
54376 var wasUpdating = layout.isUpdating();
54378 layout.beginUpdate();
54380 for(var key in state){
54381 if(typeof state[key] != "function"){
54382 var rstate = state[key];
54383 var r = layout.getRegion(key);
54386 r.resizeTo(rstate.size);
54388 if(rstate.collapsed == true){
54391 r.expand(null, true);
54397 layout.endUpdate();
54399 this.state = state;
54401 this.layout = layout;
54402 layout.on("regionresized", this.onRegionResized, this);
54403 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54404 layout.on("regionexpanded", this.onRegionExpanded, this);
54407 storeState : function(){
54408 this.provider.set(this.layout.id+"-layout-state", this.state);
54411 onRegionResized : function(region, newSize){
54412 this.state[region.getPosition()].size = newSize;
54416 onRegionCollapsed : function(region){
54417 this.state[region.getPosition()].collapsed = true;
54421 onRegionExpanded : function(region){
54422 this.state[region.getPosition()].collapsed = false;
54427 * Ext JS Library 1.1.1
54428 * Copyright(c) 2006-2007, Ext JS, LLC.
54430 * Originally Released Under LGPL - original licence link has changed is not relivant.
54433 * <script type="text/javascript">
54436 * @class Roo.ContentPanel
54437 * @extends Roo.util.Observable
54438 * @children Roo.form.Form Roo.JsonView Roo.View
54440 * A basic ContentPanel element.
54441 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54442 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54443 * @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
54444 * @cfg {Boolean} closable True if the panel can be closed/removed
54445 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54446 * @cfg {String|HTMLElement|Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54447 * @cfg {Roo.Toolbar} toolbar A toolbar for this panel
54448 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54449 * @cfg {String} title The title for this panel
54450 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54451 * @cfg {String} url Calls {@link #setUrl} with this value
54452 * @cfg {String} region [required] (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54453 * @cfg {String|Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54454 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54455 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54456 * @cfg {String} style Extra style to add to the content panel
54457 * @cfg {Roo.menu.Menu} menu popup menu
54460 * Create a new ContentPanel.
54461 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54462 * @param {String/Object} config A string to set only the title or a config object
54463 * @param {String} content (optional) Set the HTML content for this panel
54464 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54466 Roo.ContentPanel = function(el, config, content){
54470 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54474 if (config && config.parentLayout) {
54475 el = config.parentLayout.el.createChild();
54478 if(el.autoCreate){ // xtype is available if this is called from factory
54482 this.el = Roo.get(el);
54483 if(!this.el && config && config.autoCreate){
54484 if(typeof config.autoCreate == "object"){
54485 if(!config.autoCreate.id){
54486 config.autoCreate.id = config.id||el;
54488 this.el = Roo.DomHelper.append(document.body,
54489 config.autoCreate, true);
54491 this.el = Roo.DomHelper.append(document.body,
54492 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54497 this.closable = false;
54498 this.loaded = false;
54499 this.active = false;
54500 if(typeof config == "string"){
54501 this.title = config;
54503 Roo.apply(this, config);
54506 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54507 this.wrapEl = this.el.wrap();
54508 this.toolbar.container = this.el.insertSibling(false, 'before');
54509 this.toolbar = new Roo.Toolbar(this.toolbar);
54512 // xtype created footer. - not sure if will work as we normally have to render first..
54513 if (this.footer && !this.footer.el && this.footer.xtype) {
54514 if (!this.wrapEl) {
54515 this.wrapEl = this.el.wrap();
54518 this.footer.container = this.wrapEl.createChild();
54520 this.footer = Roo.factory(this.footer, Roo);
54525 this.resizeEl = Roo.get(this.resizeEl, true);
54527 this.resizeEl = this.el;
54529 // handle view.xtype
54537 * Fires when this panel is activated.
54538 * @param {Roo.ContentPanel} this
54542 * @event deactivate
54543 * Fires when this panel is activated.
54544 * @param {Roo.ContentPanel} this
54546 "deactivate" : true,
54550 * Fires when this panel is resized if fitToFrame is true.
54551 * @param {Roo.ContentPanel} this
54552 * @param {Number} width The width after any component adjustments
54553 * @param {Number} height The height after any component adjustments
54559 * Fires when this tab is created
54560 * @param {Roo.ContentPanel} this
54570 if(this.autoScroll){
54571 this.resizeEl.setStyle("overflow", "auto");
54573 // fix randome scrolling
54574 this.el.on('scroll', function() {
54575 Roo.log('fix random scolling');
54576 this.scrollTo('top',0);
54579 content = content || this.content;
54581 this.setContent(content);
54583 if(config && config.url){
54584 this.setUrl(this.url, this.params, this.loadOnce);
54589 Roo.ContentPanel.superclass.constructor.call(this);
54591 if (this.view && typeof(this.view.xtype) != 'undefined') {
54592 this.view.el = this.el.appendChild(document.createElement("div"));
54593 this.view = Roo.factory(this.view);
54594 this.view.render && this.view.render(false, '');
54598 this.fireEvent('render', this);
54601 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54603 setRegion : function(region){
54604 this.region = region;
54606 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54608 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54613 * Returns the toolbar for this Panel if one was configured.
54614 * @return {Roo.Toolbar}
54616 getToolbar : function(){
54617 return this.toolbar;
54620 setActiveState : function(active){
54621 this.active = active;
54623 this.fireEvent("deactivate", this);
54625 this.fireEvent("activate", this);
54629 * Updates this panel's element
54630 * @param {String} content The new content
54631 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54633 setContent : function(content, loadScripts){
54634 this.el.update(content, loadScripts);
54637 ignoreResize : function(w, h){
54638 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54641 this.lastSize = {width: w, height: h};
54646 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54647 * @return {Roo.UpdateManager} The UpdateManager
54649 getUpdateManager : function(){
54650 return this.el.getUpdateManager();
54653 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54654 * @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:
54657 url: "your-url.php",
54658 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54659 callback: yourFunction,
54660 scope: yourObject, //(optional scope)
54663 text: "Loading...",
54668 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54669 * 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.
54670 * @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}
54671 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54672 * @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.
54673 * @return {Roo.ContentPanel} this
54676 var um = this.el.getUpdateManager();
54677 um.update.apply(um, arguments);
54683 * 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.
54684 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54685 * @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)
54686 * @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)
54687 * @return {Roo.UpdateManager} The UpdateManager
54689 setUrl : function(url, params, loadOnce){
54690 if(this.refreshDelegate){
54691 this.removeListener("activate", this.refreshDelegate);
54693 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54694 this.on("activate", this.refreshDelegate);
54695 return this.el.getUpdateManager();
54698 _handleRefresh : function(url, params, loadOnce){
54699 if(!loadOnce || !this.loaded){
54700 var updater = this.el.getUpdateManager();
54701 updater.update(url, params, this._setLoaded.createDelegate(this));
54705 _setLoaded : function(){
54706 this.loaded = true;
54710 * Returns this panel's id
54713 getId : function(){
54718 * Returns this panel's element - used by regiosn to add.
54719 * @return {Roo.Element}
54721 getEl : function(){
54722 return this.wrapEl || this.el;
54725 adjustForComponents : function(width, height)
54727 //Roo.log('adjustForComponents ');
54728 if(this.resizeEl != this.el){
54729 width -= this.el.getFrameWidth('lr');
54730 height -= this.el.getFrameWidth('tb');
54733 var te = this.toolbar.getEl();
54734 height -= te.getHeight();
54735 te.setWidth(width);
54738 var te = this.footer.getEl();
54739 //Roo.log("footer:" + te.getHeight());
54741 height -= te.getHeight();
54742 te.setWidth(width);
54746 if(this.adjustments){
54747 width += this.adjustments[0];
54748 height += this.adjustments[1];
54750 return {"width": width, "height": height};
54753 setSize : function(width, height){
54754 if(this.fitToFrame && !this.ignoreResize(width, height)){
54755 if(this.fitContainer && this.resizeEl != this.el){
54756 this.el.setSize(width, height);
54758 var size = this.adjustForComponents(width, height);
54759 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54760 this.fireEvent('resize', this, size.width, size.height);
54765 * Returns this panel's title
54768 getTitle : function(){
54773 * Set this panel's title
54774 * @param {String} title
54776 setTitle : function(title){
54777 this.title = title;
54779 this.region.updatePanelTitle(this, title);
54784 * Returns true is this panel was configured to be closable
54785 * @return {Boolean}
54787 isClosable : function(){
54788 return this.closable;
54791 beforeSlide : function(){
54793 this.resizeEl.clip();
54796 afterSlide : function(){
54798 this.resizeEl.unclip();
54802 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54803 * Will fail silently if the {@link #setUrl} method has not been called.
54804 * This does not activate the panel, just updates its content.
54806 refresh : function(){
54807 if(this.refreshDelegate){
54808 this.loaded = false;
54809 this.refreshDelegate();
54814 * Destroys this panel
54816 destroy : function(){
54817 this.el.removeAllListeners();
54818 var tempEl = document.createElement("span");
54819 tempEl.appendChild(this.el.dom);
54820 tempEl.innerHTML = "";
54826 * form - if the content panel contains a form - this is a reference to it.
54827 * @type {Roo.form.Form}
54831 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54832 * This contains a reference to it.
54838 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54848 * @param {Object} cfg Xtype definition of item to add.
54851 addxtype : function(cfg) {
54853 if (cfg.xtype.match(/^Form$/)) {
54856 //if (this.footer) {
54857 // el = this.footer.container.insertSibling(false, 'before');
54859 el = this.el.createChild();
54862 this.form = new Roo.form.Form(cfg);
54865 if ( this.form.allItems.length) {
54866 this.form.render(el.dom);
54870 // should only have one of theses..
54871 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54872 // views.. should not be just added - used named prop 'view''
54874 cfg.el = this.el.appendChild(document.createElement("div"));
54877 var ret = new Roo.factory(cfg);
54879 ret.render && ret.render(false, ''); // render blank..
54888 * @class Roo.GridPanel
54889 * @extends Roo.ContentPanel
54891 * Create a new GridPanel.
54892 * @param {Roo.grid.Grid} grid The grid for this panel
54893 * @param {String/Object} config A string to set only the panel's title, or a config object
54895 Roo.GridPanel = function(grid, config){
54898 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54899 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54901 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54903 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54906 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54908 // xtype created footer. - not sure if will work as we normally have to render first..
54909 if (this.footer && !this.footer.el && this.footer.xtype) {
54911 this.footer.container = this.grid.getView().getFooterPanel(true);
54912 this.footer.dataSource = this.grid.dataSource;
54913 this.footer = Roo.factory(this.footer, Roo);
54917 grid.monitorWindowResize = false; // turn off autosizing
54918 grid.autoHeight = false;
54919 grid.autoWidth = false;
54921 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54924 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54925 getId : function(){
54926 return this.grid.id;
54930 * Returns the grid for this panel
54931 * @return {Roo.grid.Grid}
54933 getGrid : function(){
54937 setSize : function(width, height){
54938 if(!this.ignoreResize(width, height)){
54939 var grid = this.grid;
54940 var size = this.adjustForComponents(width, height);
54941 grid.getGridEl().setSize(size.width, size.height);
54946 beforeSlide : function(){
54947 this.grid.getView().scroller.clip();
54950 afterSlide : function(){
54951 this.grid.getView().scroller.unclip();
54954 destroy : function(){
54955 this.grid.destroy();
54957 Roo.GridPanel.superclass.destroy.call(this);
54963 * @class Roo.NestedLayoutPanel
54964 * @extends Roo.ContentPanel
54966 * Create a new NestedLayoutPanel.
54969 * @param {Roo.BorderLayout} layout [required] The layout for this panel
54970 * @param {String/Object} config A string to set only the title or a config object
54972 Roo.NestedLayoutPanel = function(layout, config)
54974 // construct with only one argument..
54975 /* FIXME - implement nicer consturctors
54976 if (layout.layout) {
54978 layout = config.layout;
54979 delete config.layout;
54981 if (layout.xtype && !layout.getEl) {
54982 // then layout needs constructing..
54983 layout = Roo.factory(layout, Roo);
54988 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54990 layout.monitorWindowResize = false; // turn off autosizing
54991 this.layout = layout;
54992 this.layout.getEl().addClass("x-layout-nested-layout");
54999 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
55001 setSize : function(width, height){
55002 if(!this.ignoreResize(width, height)){
55003 var size = this.adjustForComponents(width, height);
55004 var el = this.layout.getEl();
55005 el.setSize(size.width, size.height);
55006 var touch = el.dom.offsetWidth;
55007 this.layout.layout();
55008 // ie requires a double layout on the first pass
55009 if(Roo.isIE && !this.initialized){
55010 this.initialized = true;
55011 this.layout.layout();
55016 // activate all subpanels if not currently active..
55018 setActiveState : function(active){
55019 this.active = active;
55021 this.fireEvent("deactivate", this);
55025 this.fireEvent("activate", this);
55026 // not sure if this should happen before or after..
55027 if (!this.layout) {
55028 return; // should not happen..
55031 for (var r in this.layout.regions) {
55032 reg = this.layout.getRegion(r);
55033 if (reg.getActivePanel()) {
55034 //reg.showPanel(reg.getActivePanel()); // force it to activate..
55035 reg.setActivePanel(reg.getActivePanel());
55038 if (!reg.panels.length) {
55041 reg.showPanel(reg.getPanel(0));
55050 * Returns the nested BorderLayout for this panel
55051 * @return {Roo.BorderLayout}
55053 getLayout : function(){
55054 return this.layout;
55058 * Adds a xtype elements to the layout of the nested panel
55062 xtype : 'ContentPanel',
55069 xtype : 'NestedLayoutPanel',
55075 items : [ ... list of content panels or nested layout panels.. ]
55079 * @param {Object} cfg Xtype definition of item to add.
55081 addxtype : function(cfg) {
55082 return this.layout.addxtype(cfg);
55087 Roo.ScrollPanel = function(el, config, content){
55088 config = config || {};
55089 config.fitToFrame = true;
55090 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
55092 this.el.dom.style.overflow = "hidden";
55093 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
55094 this.el.removeClass("x-layout-inactive-content");
55095 this.el.on("mousewheel", this.onWheel, this);
55097 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
55098 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
55099 up.unselectable(); down.unselectable();
55100 up.on("click", this.scrollUp, this);
55101 down.on("click", this.scrollDown, this);
55102 up.addClassOnOver("x-scroller-btn-over");
55103 down.addClassOnOver("x-scroller-btn-over");
55104 up.addClassOnClick("x-scroller-btn-click");
55105 down.addClassOnClick("x-scroller-btn-click");
55106 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
55108 this.resizeEl = this.el;
55109 this.el = wrap; this.up = up; this.down = down;
55112 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
55114 wheelIncrement : 5,
55115 scrollUp : function(){
55116 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
55119 scrollDown : function(){
55120 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
55123 afterScroll : function(){
55124 var el = this.resizeEl;
55125 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
55126 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
55127 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
55130 setSize : function(){
55131 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
55132 this.afterScroll();
55135 onWheel : function(e){
55136 var d = e.getWheelDelta();
55137 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
55138 this.afterScroll();
55142 setContent : function(content, loadScripts){
55143 this.resizeEl.update(content, loadScripts);
55151 * @class Roo.TreePanel
55152 * @extends Roo.ContentPanel
55153 * Treepanel component
55156 * Create a new TreePanel. - defaults to fit/scoll contents.
55157 * @param {String/Object} config A string to set only the panel's title, or a config object
55159 Roo.TreePanel = function(config){
55160 var el = config.el;
55161 var tree = config.tree;
55162 delete config.tree;
55163 delete config.el; // hopefull!
55165 // wrapper for IE7 strict & safari scroll issue
55167 var treeEl = el.createChild();
55168 config.resizeEl = treeEl;
55172 Roo.TreePanel.superclass.constructor.call(this, el, config);
55175 this.tree = new Roo.tree.TreePanel(treeEl , tree);
55176 //console.log(tree);
55177 this.on('activate', function()
55179 if (this.tree.rendered) {
55182 //console.log('render tree');
55183 this.tree.render();
55185 // this should not be needed.. - it's actually the 'el' that resizes?
55186 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
55188 //this.on('resize', function (cp, w, h) {
55189 // this.tree.innerCt.setWidth(w);
55190 // this.tree.innerCt.setHeight(h);
55191 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
55198 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
55202 * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
55220 * Ext JS Library 1.1.1
55221 * Copyright(c) 2006-2007, Ext JS, LLC.
55223 * Originally Released Under LGPL - original licence link has changed is not relivant.
55226 * <script type="text/javascript">
55231 * @class Roo.ReaderLayout
55232 * @extends Roo.BorderLayout
55233 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
55234 * center region containing two nested regions (a top one for a list view and one for item preview below),
55235 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
55236 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
55237 * expedites the setup of the overall layout and regions for this common application style.
55240 var reader = new Roo.ReaderLayout();
55241 var CP = Roo.ContentPanel; // shortcut for adding
55243 reader.beginUpdate();
55244 reader.add("north", new CP("north", "North"));
55245 reader.add("west", new CP("west", {title: "West"}));
55246 reader.add("east", new CP("east", {title: "East"}));
55248 reader.regions.listView.add(new CP("listView", "List"));
55249 reader.regions.preview.add(new CP("preview", "Preview"));
55250 reader.endUpdate();
55253 * Create a new ReaderLayout
55254 * @param {Object} config Configuration options
55255 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55256 * document.body if omitted)
55258 Roo.ReaderLayout = function(config, renderTo){
55259 var c = config || {size:{}};
55260 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55261 north: c.north !== false ? Roo.apply({
55265 }, c.north) : false,
55266 west: c.west !== false ? Roo.apply({
55274 margins:{left:5,right:0,bottom:5,top:5},
55275 cmargins:{left:5,right:5,bottom:5,top:5}
55276 }, c.west) : false,
55277 east: c.east !== false ? Roo.apply({
55285 margins:{left:0,right:5,bottom:5,top:5},
55286 cmargins:{left:5,right:5,bottom:5,top:5}
55287 }, c.east) : false,
55288 center: Roo.apply({
55289 tabPosition: 'top',
55293 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55297 this.el.addClass('x-reader');
55299 this.beginUpdate();
55301 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55302 south: c.preview !== false ? Roo.apply({
55309 cmargins:{top:5,left:0, right:0, bottom:0}
55310 }, c.preview) : false,
55311 center: Roo.apply({
55317 this.add('center', new Roo.NestedLayoutPanel(inner,
55318 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55322 this.regions.preview = inner.getRegion('south');
55323 this.regions.listView = inner.getRegion('center');
55326 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55328 * Ext JS Library 1.1.1
55329 * Copyright(c) 2006-2007, Ext JS, LLC.
55331 * Originally Released Under LGPL - original licence link has changed is not relivant.
55334 * <script type="text/javascript">
55338 * @class Roo.grid.Grid
55339 * @extends Roo.util.Observable
55340 * This class represents the primary interface of a component based grid control.
55341 * <br><br>Usage:<pre><code>
55342 var grid = new Roo.grid.Grid("my-container-id", {
55345 selModel: mySelectionModel,
55346 autoSizeColumns: true,
55347 monitorWindowResize: false,
55348 trackMouseOver: true
55353 * <b>Common Problems:</b><br/>
55354 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55355 * element will correct this<br/>
55356 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55357 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55358 * are unpredictable.<br/>
55359 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55360 * grid to calculate dimensions/offsets.<br/>
55362 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55363 * The container MUST have some type of size defined for the grid to fill. The container will be
55364 * automatically set to position relative if it isn't already.
55365 * @param {Object} config A config object that sets properties on this grid.
55367 Roo.grid.Grid = function(container, config){
55368 // initialize the container
55369 this.container = Roo.get(container);
55370 this.container.update("");
55371 this.container.setStyle("overflow", "hidden");
55372 this.container.addClass('x-grid-container');
55374 this.id = this.container.id;
55376 Roo.apply(this, config);
55377 // check and correct shorthanded configs
55379 this.dataSource = this.ds;
55383 this.colModel = this.cm;
55387 this.selModel = this.sm;
55391 if (this.selModel) {
55392 this.selModel = Roo.factory(this.selModel, Roo.grid);
55393 this.sm = this.selModel;
55394 this.sm.xmodule = this.xmodule || false;
55396 if (typeof(this.colModel.config) == 'undefined') {
55397 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55398 this.cm = this.colModel;
55399 this.cm.xmodule = this.xmodule || false;
55401 if (this.dataSource) {
55402 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55403 this.ds = this.dataSource;
55404 this.ds.xmodule = this.xmodule || false;
55411 this.container.setWidth(this.width);
55415 this.container.setHeight(this.height);
55422 * The raw click event for the entire grid.
55423 * @param {Roo.EventObject} e
55428 * The raw dblclick event for the entire grid.
55429 * @param {Roo.EventObject} e
55433 * @event contextmenu
55434 * The raw contextmenu event for the entire grid.
55435 * @param {Roo.EventObject} e
55437 "contextmenu" : true,
55440 * The raw mousedown event for the entire grid.
55441 * @param {Roo.EventObject} e
55443 "mousedown" : true,
55446 * The raw mouseup event for the entire grid.
55447 * @param {Roo.EventObject} e
55452 * The raw mouseover event for the entire grid.
55453 * @param {Roo.EventObject} e
55455 "mouseover" : true,
55458 * The raw mouseout event for the entire grid.
55459 * @param {Roo.EventObject} e
55464 * The raw keypress event for the entire grid.
55465 * @param {Roo.EventObject} e
55470 * The raw keydown event for the entire grid.
55471 * @param {Roo.EventObject} e
55479 * Fires when a cell is clicked
55480 * @param {Grid} this
55481 * @param {Number} rowIndex
55482 * @param {Number} columnIndex
55483 * @param {Roo.EventObject} e
55485 "cellclick" : true,
55487 * @event celldblclick
55488 * Fires when a cell is double clicked
55489 * @param {Grid} this
55490 * @param {Number} rowIndex
55491 * @param {Number} columnIndex
55492 * @param {Roo.EventObject} e
55494 "celldblclick" : true,
55497 * Fires when a row is clicked
55498 * @param {Grid} this
55499 * @param {Number} rowIndex
55500 * @param {Roo.EventObject} e
55504 * @event rowdblclick
55505 * Fires when a row is double clicked
55506 * @param {Grid} this
55507 * @param {Number} rowIndex
55508 * @param {Roo.EventObject} e
55510 "rowdblclick" : true,
55512 * @event headerclick
55513 * Fires when a header is clicked
55514 * @param {Grid} this
55515 * @param {Number} columnIndex
55516 * @param {Roo.EventObject} e
55518 "headerclick" : true,
55520 * @event headerdblclick
55521 * Fires when a header cell is double clicked
55522 * @param {Grid} this
55523 * @param {Number} columnIndex
55524 * @param {Roo.EventObject} e
55526 "headerdblclick" : true,
55528 * @event rowcontextmenu
55529 * Fires when a row is right clicked
55530 * @param {Grid} this
55531 * @param {Number} rowIndex
55532 * @param {Roo.EventObject} e
55534 "rowcontextmenu" : true,
55536 * @event cellcontextmenu
55537 * Fires when a cell is right clicked
55538 * @param {Grid} this
55539 * @param {Number} rowIndex
55540 * @param {Number} cellIndex
55541 * @param {Roo.EventObject} e
55543 "cellcontextmenu" : true,
55545 * @event headercontextmenu
55546 * Fires when a header is right clicked
55547 * @param {Grid} this
55548 * @param {Number} columnIndex
55549 * @param {Roo.EventObject} e
55551 "headercontextmenu" : true,
55553 * @event bodyscroll
55554 * Fires when the body element is scrolled
55555 * @param {Number} scrollLeft
55556 * @param {Number} scrollTop
55558 "bodyscroll" : true,
55560 * @event columnresize
55561 * Fires when the user resizes a column
55562 * @param {Number} columnIndex
55563 * @param {Number} newSize
55565 "columnresize" : true,
55567 * @event columnmove
55568 * Fires when the user moves a column
55569 * @param {Number} oldIndex
55570 * @param {Number} newIndex
55572 "columnmove" : true,
55575 * Fires when row(s) start being dragged
55576 * @param {Grid} this
55577 * @param {Roo.GridDD} dd The drag drop object
55578 * @param {event} e The raw browser event
55580 "startdrag" : true,
55583 * Fires when a drag operation is complete
55584 * @param {Grid} this
55585 * @param {Roo.GridDD} dd The drag drop object
55586 * @param {event} e The raw browser event
55591 * Fires when dragged row(s) are dropped on a valid DD target
55592 * @param {Grid} this
55593 * @param {Roo.GridDD} dd The drag drop object
55594 * @param {String} targetId The target drag drop object
55595 * @param {event} e The raw browser event
55600 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55601 * @param {Grid} this
55602 * @param {Roo.GridDD} dd The drag drop object
55603 * @param {String} targetId The target drag drop object
55604 * @param {event} e The raw browser event
55609 * Fires when the dragged row(s) first cross another DD target while being dragged
55610 * @param {Grid} this
55611 * @param {Roo.GridDD} dd The drag drop object
55612 * @param {String} targetId The target drag drop object
55613 * @param {event} e The raw browser event
55615 "dragenter" : true,
55618 * Fires when the dragged row(s) leave another DD target while being dragged
55619 * @param {Grid} this
55620 * @param {Roo.GridDD} dd The drag drop object
55621 * @param {String} targetId The target drag drop object
55622 * @param {event} e The raw browser event
55627 * Fires when a row is rendered, so you can change add a style to it.
55628 * @param {GridView} gridview The grid view
55629 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55635 * Fires when the grid is rendered
55636 * @param {Grid} grid
55641 Roo.grid.Grid.superclass.constructor.call(this);
55643 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55646 * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
55649 * @cfg {Roo.grid.GridView} view The view that renders the grid (default = Roo.grid.GridView)
55652 * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
55655 * @cfg {Roo.grid.Store} ds The data store for the grid
55658 * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
55661 * @cfg {String} ddGroup - drag drop group.
55664 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
55668 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55670 minColumnWidth : 25,
55673 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55674 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55675 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55677 autoSizeColumns : false,
55680 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55682 autoSizeHeaders : true,
55685 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55687 monitorWindowResize : true,
55690 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55691 * rows measured to get a columns size. Default is 0 (all rows).
55693 maxRowsToMeasure : 0,
55696 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55698 trackMouseOver : true,
55701 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55704 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
55708 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55710 enableDragDrop : false,
55713 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55715 enableColumnMove : true,
55718 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55720 enableColumnHide : true,
55723 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55725 enableRowHeightSync : false,
55728 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55733 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55735 autoHeight : false,
55738 * @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.
55740 autoExpandColumn : false,
55743 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55746 autoExpandMin : 50,
55749 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55751 autoExpandMax : 1000,
55754 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55759 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55763 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55773 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55774 * of a fixed width. Default is false.
55777 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55782 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55783 * %0 is replaced with the number of selected rows.
55785 ddText : "{0} selected row{1}",
55789 * Called once after all setup has been completed and the grid is ready to be rendered.
55790 * @return {Roo.grid.Grid} this
55792 render : function()
55794 var c = this.container;
55795 // try to detect autoHeight/width mode
55796 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55797 this.autoHeight = true;
55799 var view = this.getView();
55802 c.on("click", this.onClick, this);
55803 c.on("dblclick", this.onDblClick, this);
55804 c.on("contextmenu", this.onContextMenu, this);
55805 c.on("keydown", this.onKeyDown, this);
55807 c.on("touchstart", this.onTouchStart, this);
55810 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55812 this.getSelectionModel().init(this);
55817 this.loadMask = new Roo.LoadMask(this.container,
55818 Roo.apply({store:this.dataSource}, this.loadMask));
55822 if (this.toolbar && this.toolbar.xtype) {
55823 this.toolbar.container = this.getView().getHeaderPanel(true);
55824 this.toolbar = new Roo.Toolbar(this.toolbar);
55826 if (this.footer && this.footer.xtype) {
55827 this.footer.dataSource = this.getDataSource();
55828 this.footer.container = this.getView().getFooterPanel(true);
55829 this.footer = Roo.factory(this.footer, Roo);
55831 if (this.dropTarget && this.dropTarget.xtype) {
55832 delete this.dropTarget.xtype;
55833 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55837 this.rendered = true;
55838 this.fireEvent('render', this);
55843 * Reconfigures the grid to use a different Store and Column Model.
55844 * The View will be bound to the new objects and refreshed.
55845 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55846 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55848 reconfigure : function(dataSource, colModel){
55850 this.loadMask.destroy();
55851 this.loadMask = new Roo.LoadMask(this.container,
55852 Roo.apply({store:dataSource}, this.loadMask));
55854 this.view.bind(dataSource, colModel);
55855 this.dataSource = dataSource;
55856 this.colModel = colModel;
55857 this.view.refresh(true);
55861 * Add's a column, default at the end..
55863 * @param {int} position to add (default end)
55864 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55866 addColumns : function(pos, ar)
55869 for (var i =0;i< ar.length;i++) {
55871 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55872 this.cm.lookup[cfg.id] = cfg;
55876 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55877 pos = this.cm.config.length; //this.cm.config.push(cfg);
55879 pos = Math.max(0,pos);
55882 this.cm.config.splice.apply(this.cm.config, ar);
55886 this.view.generateRules(this.cm);
55887 this.view.refresh(true);
55895 onKeyDown : function(e){
55896 this.fireEvent("keydown", e);
55900 * Destroy this grid.
55901 * @param {Boolean} removeEl True to remove the element
55903 destroy : function(removeEl, keepListeners){
55905 this.loadMask.destroy();
55907 var c = this.container;
55908 c.removeAllListeners();
55909 this.view.destroy();
55910 this.colModel.purgeListeners();
55911 if(!keepListeners){
55912 this.purgeListeners();
55915 if(removeEl === true){
55921 processEvent : function(name, e){
55922 // does this fire select???
55923 //Roo.log('grid:processEvent ' + name);
55925 if (name != 'touchstart' ) {
55926 this.fireEvent(name, e);
55929 var t = e.getTarget();
55931 var header = v.findHeaderIndex(t);
55932 if(header !== false){
55933 var ename = name == 'touchstart' ? 'click' : name;
55935 this.fireEvent("header" + ename, this, header, e);
55937 var row = v.findRowIndex(t);
55938 var cell = v.findCellIndex(t);
55939 if (name == 'touchstart') {
55940 // first touch is always a click.
55941 // hopefull this happens after selection is updated.?
55944 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55945 var cs = this.selModel.getSelectedCell();
55946 if (row == cs[0] && cell == cs[1]){
55950 if (typeof(this.selModel.getSelections) != 'undefined') {
55951 var cs = this.selModel.getSelections();
55952 var ds = this.dataSource;
55953 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55964 this.fireEvent("row" + name, this, row, e);
55965 if(cell !== false){
55966 this.fireEvent("cell" + name, this, row, cell, e);
55973 onClick : function(e){
55974 this.processEvent("click", e);
55977 onTouchStart : function(e){
55978 this.processEvent("touchstart", e);
55982 onContextMenu : function(e, t){
55983 this.processEvent("contextmenu", e);
55987 onDblClick : function(e){
55988 this.processEvent("dblclick", e);
55992 walkCells : function(row, col, step, fn, scope){
55993 var cm = this.colModel, clen = cm.getColumnCount();
55994 var ds = this.dataSource, rlen = ds.getCount(), first = true;
56006 if(fn.call(scope || this, row, col, cm) === true){
56024 if(fn.call(scope || this, row, col, cm) === true){
56036 getSelections : function(){
56037 return this.selModel.getSelections();
56041 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
56042 * but if manual update is required this method will initiate it.
56044 autoSize : function(){
56046 this.view.layout();
56047 if(this.view.adjustForScroll){
56048 this.view.adjustForScroll();
56054 * Returns the grid's underlying element.
56055 * @return {Element} The element
56057 getGridEl : function(){
56058 return this.container;
56061 // private for compatibility, overridden by editor grid
56062 stopEditing : function(){},
56065 * Returns the grid's SelectionModel.
56066 * @return {SelectionModel}
56068 getSelectionModel : function(){
56069 if(!this.selModel){
56070 this.selModel = new Roo.grid.RowSelectionModel();
56072 return this.selModel;
56076 * Returns the grid's DataSource.
56077 * @return {DataSource}
56079 getDataSource : function(){
56080 return this.dataSource;
56084 * Returns the grid's ColumnModel.
56085 * @return {ColumnModel}
56087 getColumnModel : function(){
56088 return this.colModel;
56092 * Returns the grid's GridView object.
56093 * @return {GridView}
56095 getView : function(){
56097 this.view = new Roo.grid.GridView(this.viewConfig);
56098 this.relayEvents(this.view, [
56099 "beforerowremoved", "beforerowsinserted",
56100 "beforerefresh", "rowremoved",
56101 "rowsinserted", "rowupdated" ,"refresh"
56107 * Called to get grid's drag proxy text, by default returns this.ddText.
56108 * Override this to put something different in the dragged text.
56111 getDragDropText : function(){
56112 var count = this.selModel.getCount();
56113 return String.format(this.ddText, count, count == 1 ? '' : 's');
56118 * Ext JS Library 1.1.1
56119 * Copyright(c) 2006-2007, Ext JS, LLC.
56121 * Originally Released Under LGPL - original licence link has changed is not relivant.
56124 * <script type="text/javascript">
56127 * @class Roo.grid.AbstractGridView
56128 * @extends Roo.util.Observable
56130 * Abstract base class for grid Views
56133 Roo.grid.AbstractGridView = function(){
56137 "beforerowremoved" : true,
56138 "beforerowsinserted" : true,
56139 "beforerefresh" : true,
56140 "rowremoved" : true,
56141 "rowsinserted" : true,
56142 "rowupdated" : true,
56145 Roo.grid.AbstractGridView.superclass.constructor.call(this);
56148 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
56149 rowClass : "x-grid-row",
56150 cellClass : "x-grid-cell",
56151 tdClass : "x-grid-td",
56152 hdClass : "x-grid-hd",
56153 splitClass : "x-grid-hd-split",
56155 init: function(grid){
56157 var cid = this.grid.getGridEl().id;
56158 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
56159 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
56160 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
56161 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
56164 getColumnRenderers : function(){
56165 var renderers = [];
56166 var cm = this.grid.colModel;
56167 var colCount = cm.getColumnCount();
56168 for(var i = 0; i < colCount; i++){
56169 renderers[i] = cm.getRenderer(i);
56174 getColumnIds : function(){
56176 var cm = this.grid.colModel;
56177 var colCount = cm.getColumnCount();
56178 for(var i = 0; i < colCount; i++){
56179 ids[i] = cm.getColumnId(i);
56184 getDataIndexes : function(){
56185 if(!this.indexMap){
56186 this.indexMap = this.buildIndexMap();
56188 return this.indexMap.colToData;
56191 getColumnIndexByDataIndex : function(dataIndex){
56192 if(!this.indexMap){
56193 this.indexMap = this.buildIndexMap();
56195 return this.indexMap.dataToCol[dataIndex];
56199 * Set a css style for a column dynamically.
56200 * @param {Number} colIndex The index of the column
56201 * @param {String} name The css property name
56202 * @param {String} value The css value
56204 setCSSStyle : function(colIndex, name, value){
56205 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
56206 Roo.util.CSS.updateRule(selector, name, value);
56209 generateRules : function(cm){
56210 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
56211 Roo.util.CSS.removeStyleSheet(rulesId);
56212 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56213 var cid = cm.getColumnId(i);
56214 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
56215 this.tdSelector, cid, " {\n}\n",
56216 this.hdSelector, cid, " {\n}\n",
56217 this.splitSelector, cid, " {\n}\n");
56219 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56223 * Ext JS Library 1.1.1
56224 * Copyright(c) 2006-2007, Ext JS, LLC.
56226 * Originally Released Under LGPL - original licence link has changed is not relivant.
56229 * <script type="text/javascript">
56233 // This is a support class used internally by the Grid components
56234 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
56236 this.view = grid.getView();
56237 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56238 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
56240 this.setHandleElId(Roo.id(hd));
56241 this.setOuterHandleElId(Roo.id(hd2));
56243 this.scroll = false;
56245 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
56247 getDragData : function(e){
56248 var t = Roo.lib.Event.getTarget(e);
56249 var h = this.view.findHeaderCell(t);
56251 return {ddel: h.firstChild, header:h};
56256 onInitDrag : function(e){
56257 this.view.headersDisabled = true;
56258 var clone = this.dragData.ddel.cloneNode(true);
56259 clone.id = Roo.id();
56260 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
56261 this.proxy.update(clone);
56265 afterValidDrop : function(){
56267 setTimeout(function(){
56268 v.headersDisabled = false;
56272 afterInvalidDrop : function(){
56274 setTimeout(function(){
56275 v.headersDisabled = false;
56281 * Ext JS Library 1.1.1
56282 * Copyright(c) 2006-2007, Ext JS, LLC.
56284 * Originally Released Under LGPL - original licence link has changed is not relivant.
56287 * <script type="text/javascript">
56290 // This is a support class used internally by the Grid components
56291 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56293 this.view = grid.getView();
56294 // split the proxies so they don't interfere with mouse events
56295 this.proxyTop = Roo.DomHelper.append(document.body, {
56296 cls:"col-move-top", html:" "
56298 this.proxyBottom = Roo.DomHelper.append(document.body, {
56299 cls:"col-move-bottom", html:" "
56301 this.proxyTop.hide = this.proxyBottom.hide = function(){
56302 this.setLeftTop(-100,-100);
56303 this.setStyle("visibility", "hidden");
56305 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56306 // temporarily disabled
56307 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56308 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56310 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56311 proxyOffsets : [-4, -9],
56312 fly: Roo.Element.fly,
56314 getTargetFromEvent : function(e){
56315 var t = Roo.lib.Event.getTarget(e);
56316 var cindex = this.view.findCellIndex(t);
56317 if(cindex !== false){
56318 return this.view.getHeaderCell(cindex);
56323 nextVisible : function(h){
56324 var v = this.view, cm = this.grid.colModel;
56327 if(!cm.isHidden(v.getCellIndex(h))){
56335 prevVisible : function(h){
56336 var v = this.view, cm = this.grid.colModel;
56339 if(!cm.isHidden(v.getCellIndex(h))){
56347 positionIndicator : function(h, n, e){
56348 var x = Roo.lib.Event.getPageX(e);
56349 var r = Roo.lib.Dom.getRegion(n.firstChild);
56350 var px, pt, py = r.top + this.proxyOffsets[1];
56351 if((r.right - x) <= (r.right-r.left)/2){
56352 px = r.right+this.view.borderWidth;
56358 var oldIndex = this.view.getCellIndex(h);
56359 var newIndex = this.view.getCellIndex(n);
56361 if(this.grid.colModel.isFixed(newIndex)){
56365 var locked = this.grid.colModel.isLocked(newIndex);
56370 if(oldIndex < newIndex){
56373 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56376 px += this.proxyOffsets[0];
56377 this.proxyTop.setLeftTop(px, py);
56378 this.proxyTop.show();
56379 if(!this.bottomOffset){
56380 this.bottomOffset = this.view.mainHd.getHeight();
56382 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56383 this.proxyBottom.show();
56387 onNodeEnter : function(n, dd, e, data){
56388 if(data.header != n){
56389 this.positionIndicator(data.header, n, e);
56393 onNodeOver : function(n, dd, e, data){
56394 var result = false;
56395 if(data.header != n){
56396 result = this.positionIndicator(data.header, n, e);
56399 this.proxyTop.hide();
56400 this.proxyBottom.hide();
56402 return result ? this.dropAllowed : this.dropNotAllowed;
56405 onNodeOut : function(n, dd, e, data){
56406 this.proxyTop.hide();
56407 this.proxyBottom.hide();
56410 onNodeDrop : function(n, dd, e, data){
56411 var h = data.header;
56413 var cm = this.grid.colModel;
56414 var x = Roo.lib.Event.getPageX(e);
56415 var r = Roo.lib.Dom.getRegion(n.firstChild);
56416 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56417 var oldIndex = this.view.getCellIndex(h);
56418 var newIndex = this.view.getCellIndex(n);
56419 var locked = cm.isLocked(newIndex);
56423 if(oldIndex < newIndex){
56426 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56429 cm.setLocked(oldIndex, locked, true);
56430 cm.moveColumn(oldIndex, newIndex);
56431 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56439 * Ext JS Library 1.1.1
56440 * Copyright(c) 2006-2007, Ext JS, LLC.
56442 * Originally Released Under LGPL - original licence link has changed is not relivant.
56445 * <script type="text/javascript">
56449 * @class Roo.grid.GridView
56450 * @extends Roo.util.Observable
56453 * @param {Object} config
56455 Roo.grid.GridView = function(config){
56456 Roo.grid.GridView.superclass.constructor.call(this);
56459 Roo.apply(this, config);
56462 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56464 unselectable : 'unselectable="on"',
56465 unselectableCls : 'x-unselectable',
56468 rowClass : "x-grid-row",
56470 cellClass : "x-grid-col",
56472 tdClass : "x-grid-td",
56474 hdClass : "x-grid-hd",
56476 splitClass : "x-grid-split",
56478 sortClasses : ["sort-asc", "sort-desc"],
56480 enableMoveAnim : false,
56484 dh : Roo.DomHelper,
56486 fly : Roo.Element.fly,
56488 css : Roo.util.CSS,
56494 scrollIncrement : 22,
56496 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56498 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56500 bind : function(ds, cm){
56502 this.ds.un("load", this.onLoad, this);
56503 this.ds.un("datachanged", this.onDataChange, this);
56504 this.ds.un("add", this.onAdd, this);
56505 this.ds.un("remove", this.onRemove, this);
56506 this.ds.un("update", this.onUpdate, this);
56507 this.ds.un("clear", this.onClear, this);
56510 ds.on("load", this.onLoad, this);
56511 ds.on("datachanged", this.onDataChange, this);
56512 ds.on("add", this.onAdd, this);
56513 ds.on("remove", this.onRemove, this);
56514 ds.on("update", this.onUpdate, this);
56515 ds.on("clear", this.onClear, this);
56520 this.cm.un("widthchange", this.onColWidthChange, this);
56521 this.cm.un("headerchange", this.onHeaderChange, this);
56522 this.cm.un("hiddenchange", this.onHiddenChange, this);
56523 this.cm.un("columnmoved", this.onColumnMove, this);
56524 this.cm.un("columnlockchange", this.onColumnLock, this);
56527 this.generateRules(cm);
56528 cm.on("widthchange", this.onColWidthChange, this);
56529 cm.on("headerchange", this.onHeaderChange, this);
56530 cm.on("hiddenchange", this.onHiddenChange, this);
56531 cm.on("columnmoved", this.onColumnMove, this);
56532 cm.on("columnlockchange", this.onColumnLock, this);
56537 init: function(grid){
56538 Roo.grid.GridView.superclass.init.call(this, grid);
56540 this.bind(grid.dataSource, grid.colModel);
56542 grid.on("headerclick", this.handleHeaderClick, this);
56544 if(grid.trackMouseOver){
56545 grid.on("mouseover", this.onRowOver, this);
56546 grid.on("mouseout", this.onRowOut, this);
56548 grid.cancelTextSelection = function(){};
56549 this.gridId = grid.id;
56551 var tpls = this.templates || {};
56554 tpls.master = new Roo.Template(
56555 '<div class="x-grid" hidefocus="true">',
56556 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56557 '<div class="x-grid-topbar"></div>',
56558 '<div class="x-grid-scroller"><div></div></div>',
56559 '<div class="x-grid-locked">',
56560 '<div class="x-grid-header">{lockedHeader}</div>',
56561 '<div class="x-grid-body">{lockedBody}</div>',
56563 '<div class="x-grid-viewport">',
56564 '<div class="x-grid-header">{header}</div>',
56565 '<div class="x-grid-body">{body}</div>',
56567 '<div class="x-grid-bottombar"></div>',
56569 '<div class="x-grid-resize-proxy"> </div>',
56572 tpls.master.disableformats = true;
56576 tpls.header = new Roo.Template(
56577 '<table border="0" cellspacing="0" cellpadding="0">',
56578 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56581 tpls.header.disableformats = true;
56583 tpls.header.compile();
56586 tpls.hcell = new Roo.Template(
56587 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56588 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56591 tpls.hcell.disableFormats = true;
56593 tpls.hcell.compile();
56596 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56597 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56598 tpls.hsplit.disableFormats = true;
56600 tpls.hsplit.compile();
56603 tpls.body = new Roo.Template(
56604 '<table border="0" cellspacing="0" cellpadding="0">',
56605 "<tbody>{rows}</tbody>",
56608 tpls.body.disableFormats = true;
56610 tpls.body.compile();
56613 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56614 tpls.row.disableFormats = true;
56616 tpls.row.compile();
56619 tpls.cell = new Roo.Template(
56620 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56621 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56622 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56625 tpls.cell.disableFormats = true;
56627 tpls.cell.compile();
56629 this.templates = tpls;
56632 // remap these for backwards compat
56633 onColWidthChange : function(){
56634 this.updateColumns.apply(this, arguments);
56636 onHeaderChange : function(){
56637 this.updateHeaders.apply(this, arguments);
56639 onHiddenChange : function(){
56640 this.handleHiddenChange.apply(this, arguments);
56642 onColumnMove : function(){
56643 this.handleColumnMove.apply(this, arguments);
56645 onColumnLock : function(){
56646 this.handleLockChange.apply(this, arguments);
56649 onDataChange : function(){
56651 this.updateHeaderSortState();
56654 onClear : function(){
56658 onUpdate : function(ds, record){
56659 this.refreshRow(record);
56662 refreshRow : function(record){
56663 var ds = this.ds, index;
56664 if(typeof record == 'number'){
56666 record = ds.getAt(index);
56668 index = ds.indexOf(record);
56670 this.insertRows(ds, index, index, true);
56671 this.onRemove(ds, record, index+1, true);
56672 this.syncRowHeights(index, index);
56674 this.fireEvent("rowupdated", this, index, record);
56677 onAdd : function(ds, records, index){
56678 this.insertRows(ds, index, index + (records.length-1));
56681 onRemove : function(ds, record, index, isUpdate){
56682 if(isUpdate !== true){
56683 this.fireEvent("beforerowremoved", this, index, record);
56685 var bt = this.getBodyTable(), lt = this.getLockedTable();
56686 if(bt.rows[index]){
56687 bt.firstChild.removeChild(bt.rows[index]);
56689 if(lt.rows[index]){
56690 lt.firstChild.removeChild(lt.rows[index]);
56692 if(isUpdate !== true){
56693 this.stripeRows(index);
56694 this.syncRowHeights(index, index);
56696 this.fireEvent("rowremoved", this, index, record);
56700 onLoad : function(){
56701 this.scrollToTop();
56705 * Scrolls the grid to the top
56707 scrollToTop : function(){
56709 this.scroller.dom.scrollTop = 0;
56715 * Gets a panel in the header of the grid that can be used for toolbars etc.
56716 * After modifying the contents of this panel a call to grid.autoSize() may be
56717 * required to register any changes in size.
56718 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56719 * @return Roo.Element
56721 getHeaderPanel : function(doShow){
56723 this.headerPanel.show();
56725 return this.headerPanel;
56729 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56730 * After modifying the contents of this panel a call to grid.autoSize() may be
56731 * required to register any changes in size.
56732 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56733 * @return Roo.Element
56735 getFooterPanel : function(doShow){
56737 this.footerPanel.show();
56739 return this.footerPanel;
56742 initElements : function(){
56743 var E = Roo.Element;
56744 var el = this.grid.getGridEl().dom.firstChild;
56745 var cs = el.childNodes;
56747 this.el = new E(el);
56749 this.focusEl = new E(el.firstChild);
56750 this.focusEl.swallowEvent("click", true);
56752 this.headerPanel = new E(cs[1]);
56753 this.headerPanel.enableDisplayMode("block");
56755 this.scroller = new E(cs[2]);
56756 this.scrollSizer = new E(this.scroller.dom.firstChild);
56758 this.lockedWrap = new E(cs[3]);
56759 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56760 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56762 this.mainWrap = new E(cs[4]);
56763 this.mainHd = new E(this.mainWrap.dom.firstChild);
56764 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56766 this.footerPanel = new E(cs[5]);
56767 this.footerPanel.enableDisplayMode("block");
56769 this.resizeProxy = new E(cs[6]);
56771 this.headerSelector = String.format(
56772 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56773 this.lockedHd.id, this.mainHd.id
56776 this.splitterSelector = String.format(
56777 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56778 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56781 idToCssName : function(s)
56783 return s.replace(/[^a-z0-9]+/ig, '-');
56786 getHeaderCell : function(index){
56787 return Roo.DomQuery.select(this.headerSelector)[index];
56790 getHeaderCellMeasure : function(index){
56791 return this.getHeaderCell(index).firstChild;
56794 getHeaderCellText : function(index){
56795 return this.getHeaderCell(index).firstChild.firstChild;
56798 getLockedTable : function(){
56799 return this.lockedBody.dom.firstChild;
56802 getBodyTable : function(){
56803 return this.mainBody.dom.firstChild;
56806 getLockedRow : function(index){
56807 return this.getLockedTable().rows[index];
56810 getRow : function(index){
56811 return this.getBodyTable().rows[index];
56814 getRowComposite : function(index){
56816 this.rowEl = new Roo.CompositeElementLite();
56818 var els = [], lrow, mrow;
56819 if(lrow = this.getLockedRow(index)){
56822 if(mrow = this.getRow(index)){
56825 this.rowEl.elements = els;
56829 * Gets the 'td' of the cell
56831 * @param {Integer} rowIndex row to select
56832 * @param {Integer} colIndex column to select
56836 getCell : function(rowIndex, colIndex){
56837 var locked = this.cm.getLockedCount();
56839 if(colIndex < locked){
56840 source = this.lockedBody.dom.firstChild;
56842 source = this.mainBody.dom.firstChild;
56843 colIndex -= locked;
56845 return source.rows[rowIndex].childNodes[colIndex];
56848 getCellText : function(rowIndex, colIndex){
56849 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56852 getCellBox : function(cell){
56853 var b = this.fly(cell).getBox();
56854 if(Roo.isOpera){ // opera fails to report the Y
56855 b.y = cell.offsetTop + this.mainBody.getY();
56860 getCellIndex : function(cell){
56861 var id = String(cell.className).match(this.cellRE);
56863 return parseInt(id[1], 10);
56868 findHeaderIndex : function(n){
56869 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56870 return r ? this.getCellIndex(r) : false;
56873 findHeaderCell : function(n){
56874 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56875 return r ? r : false;
56878 findRowIndex : function(n){
56882 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56883 return r ? r.rowIndex : false;
56886 findCellIndex : function(node){
56887 var stop = this.el.dom;
56888 while(node && node != stop){
56889 if(this.findRE.test(node.className)){
56890 return this.getCellIndex(node);
56892 node = node.parentNode;
56897 getColumnId : function(index){
56898 return this.cm.getColumnId(index);
56901 getSplitters : function()
56903 if(this.splitterSelector){
56904 return Roo.DomQuery.select(this.splitterSelector);
56910 getSplitter : function(index){
56911 return this.getSplitters()[index];
56914 onRowOver : function(e, t){
56916 if((row = this.findRowIndex(t)) !== false){
56917 this.getRowComposite(row).addClass("x-grid-row-over");
56921 onRowOut : function(e, t){
56923 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56924 this.getRowComposite(row).removeClass("x-grid-row-over");
56928 renderHeaders : function(){
56930 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56931 var cb = [], lb = [], sb = [], lsb = [], p = {};
56932 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56933 p.cellId = "x-grid-hd-0-" + i;
56934 p.splitId = "x-grid-csplit-0-" + i;
56935 p.id = cm.getColumnId(i);
56936 p.value = cm.getColumnHeader(i) || "";
56937 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56938 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56939 if(!cm.isLocked(i)){
56940 cb[cb.length] = ct.apply(p);
56941 sb[sb.length] = st.apply(p);
56943 lb[lb.length] = ct.apply(p);
56944 lsb[lsb.length] = st.apply(p);
56947 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56948 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56951 updateHeaders : function(){
56952 var html = this.renderHeaders();
56953 this.lockedHd.update(html[0]);
56954 this.mainHd.update(html[1]);
56958 * Focuses the specified row.
56959 * @param {Number} row The row index
56961 focusRow : function(row)
56963 //Roo.log('GridView.focusRow');
56964 var x = this.scroller.dom.scrollLeft;
56965 this.focusCell(row, 0, false);
56966 this.scroller.dom.scrollLeft = x;
56970 * Focuses the specified cell.
56971 * @param {Number} row The row index
56972 * @param {Number} col The column index
56973 * @param {Boolean} hscroll false to disable horizontal scrolling
56975 focusCell : function(row, col, hscroll)
56977 //Roo.log('GridView.focusCell');
56978 var el = this.ensureVisible(row, col, hscroll);
56979 this.focusEl.alignTo(el, "tl-tl");
56981 this.focusEl.focus();
56983 this.focusEl.focus.defer(1, this.focusEl);
56988 * Scrolls the specified cell into view
56989 * @param {Number} row The row index
56990 * @param {Number} col The column index
56991 * @param {Boolean} hscroll false to disable horizontal scrolling
56993 ensureVisible : function(row, col, hscroll)
56995 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56996 //return null; //disable for testing.
56997 if(typeof row != "number"){
56998 row = row.rowIndex;
57000 if(row < 0 && row >= this.ds.getCount()){
57003 col = (col !== undefined ? col : 0);
57004 var cm = this.grid.colModel;
57005 while(cm.isHidden(col)){
57009 var el = this.getCell(row, col);
57013 var c = this.scroller.dom;
57015 var ctop = parseInt(el.offsetTop, 10);
57016 var cleft = parseInt(el.offsetLeft, 10);
57017 var cbot = ctop + el.offsetHeight;
57018 var cright = cleft + el.offsetWidth;
57020 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
57021 var stop = parseInt(c.scrollTop, 10);
57022 var sleft = parseInt(c.scrollLeft, 10);
57023 var sbot = stop + ch;
57024 var sright = sleft + c.clientWidth;
57026 Roo.log('GridView.ensureVisible:' +
57028 ' c.clientHeight:' + c.clientHeight +
57029 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
57037 c.scrollTop = ctop;
57038 //Roo.log("set scrolltop to ctop DISABLE?");
57039 }else if(cbot > sbot){
57040 //Roo.log("set scrolltop to cbot-ch");
57041 c.scrollTop = cbot-ch;
57044 if(hscroll !== false){
57046 c.scrollLeft = cleft;
57047 }else if(cright > sright){
57048 c.scrollLeft = cright-c.clientWidth;
57055 updateColumns : function(){
57056 this.grid.stopEditing();
57057 var cm = this.grid.colModel, colIds = this.getColumnIds();
57058 //var totalWidth = cm.getTotalWidth();
57060 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57061 //if(cm.isHidden(i)) continue;
57062 var w = cm.getColumnWidth(i);
57063 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
57064 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
57066 this.updateSplitters();
57069 generateRules : function(cm){
57070 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
57071 Roo.util.CSS.removeStyleSheet(rulesId);
57072 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57073 var cid = cm.getColumnId(i);
57075 if(cm.config[i].align){
57076 align = 'text-align:'+cm.config[i].align+';';
57079 if(cm.isHidden(i)){
57080 hidden = 'display:none;';
57082 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
57084 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
57085 this.hdSelector, cid, " {\n", align, width, "}\n",
57086 this.tdSelector, cid, " {\n",hidden,"\n}\n",
57087 this.splitSelector, cid, " {\n", hidden , "\n}\n");
57089 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
57092 updateSplitters : function(){
57093 var cm = this.cm, s = this.getSplitters();
57094 if(s){ // splitters not created yet
57095 var pos = 0, locked = true;
57096 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57097 if(cm.isHidden(i)) {
57100 var w = cm.getColumnWidth(i); // make sure it's a number
57101 if(!cm.isLocked(i) && locked){
57106 s[i].style.left = (pos-this.splitOffset) + "px";
57111 handleHiddenChange : function(colModel, colIndex, hidden){
57113 this.hideColumn(colIndex);
57115 this.unhideColumn(colIndex);
57119 hideColumn : function(colIndex){
57120 var cid = this.getColumnId(colIndex);
57121 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
57122 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
57124 this.updateHeaders();
57126 this.updateSplitters();
57130 unhideColumn : function(colIndex){
57131 var cid = this.getColumnId(colIndex);
57132 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
57133 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
57136 this.updateHeaders();
57138 this.updateSplitters();
57142 insertRows : function(dm, firstRow, lastRow, isUpdate){
57143 if(firstRow == 0 && lastRow == dm.getCount()-1){
57147 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
57149 var s = this.getScrollState();
57150 var markup = this.renderRows(firstRow, lastRow);
57151 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
57152 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
57153 this.restoreScroll(s);
57155 this.fireEvent("rowsinserted", this, firstRow, lastRow);
57156 this.syncRowHeights(firstRow, lastRow);
57157 this.stripeRows(firstRow);
57163 bufferRows : function(markup, target, index){
57164 var before = null, trows = target.rows, tbody = target.tBodies[0];
57165 if(index < trows.length){
57166 before = trows[index];
57168 var b = document.createElement("div");
57169 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
57170 var rows = b.firstChild.rows;
57171 for(var i = 0, len = rows.length; i < len; i++){
57173 tbody.insertBefore(rows[0], before);
57175 tbody.appendChild(rows[0]);
57182 deleteRows : function(dm, firstRow, lastRow){
57183 if(dm.getRowCount()<1){
57184 this.fireEvent("beforerefresh", this);
57185 this.mainBody.update("");
57186 this.lockedBody.update("");
57187 this.fireEvent("refresh", this);
57189 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
57190 var bt = this.getBodyTable();
57191 var tbody = bt.firstChild;
57192 var rows = bt.rows;
57193 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
57194 tbody.removeChild(rows[firstRow]);
57196 this.stripeRows(firstRow);
57197 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
57201 updateRows : function(dataSource, firstRow, lastRow){
57202 var s = this.getScrollState();
57204 this.restoreScroll(s);
57207 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
57211 this.updateHeaderSortState();
57214 getScrollState : function(){
57216 var sb = this.scroller.dom;
57217 return {left: sb.scrollLeft, top: sb.scrollTop};
57220 stripeRows : function(startRow){
57221 if(!this.grid.stripeRows || this.ds.getCount() < 1){
57224 startRow = startRow || 0;
57225 var rows = this.getBodyTable().rows;
57226 var lrows = this.getLockedTable().rows;
57227 var cls = ' x-grid-row-alt ';
57228 for(var i = startRow, len = rows.length; i < len; i++){
57229 var row = rows[i], lrow = lrows[i];
57230 var isAlt = ((i+1) % 2 == 0);
57231 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
57232 if(isAlt == hasAlt){
57236 row.className += " x-grid-row-alt";
57238 row.className = row.className.replace("x-grid-row-alt", "");
57241 lrow.className = row.className;
57246 restoreScroll : function(state){
57247 //Roo.log('GridView.restoreScroll');
57248 var sb = this.scroller.dom;
57249 sb.scrollLeft = state.left;
57250 sb.scrollTop = state.top;
57254 syncScroll : function(){
57255 //Roo.log('GridView.syncScroll');
57256 var sb = this.scroller.dom;
57257 var sh = this.mainHd.dom;
57258 var bs = this.mainBody.dom;
57259 var lv = this.lockedBody.dom;
57260 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
57261 lv.scrollTop = bs.scrollTop = sb.scrollTop;
57264 handleScroll : function(e){
57266 var sb = this.scroller.dom;
57267 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
57271 handleWheel : function(e){
57272 var d = e.getWheelDelta();
57273 this.scroller.dom.scrollTop -= d*22;
57274 // set this here to prevent jumpy scrolling on large tables
57275 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
57279 renderRows : function(startRow, endRow){
57280 // pull in all the crap needed to render rows
57281 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
57282 var colCount = cm.getColumnCount();
57284 if(ds.getCount() < 1){
57288 // build a map for all the columns
57290 for(var i = 0; i < colCount; i++){
57291 var name = cm.getDataIndex(i);
57293 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57294 renderer : cm.getRenderer(i),
57295 id : cm.getColumnId(i),
57296 locked : cm.isLocked(i),
57297 has_editor : cm.isCellEditable(i)
57301 startRow = startRow || 0;
57302 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57304 // records to render
57305 var rs = ds.getRange(startRow, endRow);
57307 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57310 // As much as I hate to duplicate code, this was branched because FireFox really hates
57311 // [].join("") on strings. The performance difference was substantial enough to
57312 // branch this function
57313 doRender : Roo.isGecko ?
57314 function(cs, rs, ds, startRow, colCount, stripe){
57315 var ts = this.templates, ct = ts.cell, rt = ts.row;
57317 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57319 var hasListener = this.grid.hasListener('rowclass');
57321 for(var j = 0, len = rs.length; j < len; j++){
57322 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57323 for(var i = 0; i < colCount; i++){
57325 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57327 p.css = p.attr = "";
57328 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57329 if(p.value == undefined || p.value === "") {
57330 p.value = " ";
57333 p.css += ' x-grid-editable-cell';
57335 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57336 p.css += ' x-grid-dirty-cell';
57338 var markup = ct.apply(p);
57346 if(stripe && ((rowIndex+1) % 2 == 0)){
57347 alt.push("x-grid-row-alt")
57350 alt.push( " x-grid-dirty-row");
57353 if(this.getRowClass){
57354 alt.push(this.getRowClass(r, rowIndex));
57360 rowIndex : rowIndex,
57363 this.grid.fireEvent('rowclass', this, rowcfg);
57364 alt.push(rowcfg.rowClass);
57366 rp.alt = alt.join(" ");
57367 lbuf+= rt.apply(rp);
57369 buf+= rt.apply(rp);
57371 return [lbuf, buf];
57373 function(cs, rs, ds, startRow, colCount, stripe){
57374 var ts = this.templates, ct = ts.cell, rt = ts.row;
57376 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57377 var hasListener = this.grid.hasListener('rowclass');
57380 for(var j = 0, len = rs.length; j < len; j++){
57381 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57382 for(var i = 0; i < colCount; i++){
57384 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57386 p.css = p.attr = "";
57387 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57388 if(p.value == undefined || p.value === "") {
57389 p.value = " ";
57393 p.css += ' x-grid-editable-cell';
57395 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57396 p.css += ' x-grid-dirty-cell'
57399 var markup = ct.apply(p);
57401 cb[cb.length] = markup;
57403 lcb[lcb.length] = markup;
57407 if(stripe && ((rowIndex+1) % 2 == 0)){
57408 alt.push( "x-grid-row-alt");
57411 alt.push(" x-grid-dirty-row");
57414 if(this.getRowClass){
57415 alt.push( this.getRowClass(r, rowIndex));
57421 rowIndex : rowIndex,
57424 this.grid.fireEvent('rowclass', this, rowcfg);
57425 alt.push(rowcfg.rowClass);
57428 rp.alt = alt.join(" ");
57429 rp.cells = lcb.join("");
57430 lbuf[lbuf.length] = rt.apply(rp);
57431 rp.cells = cb.join("");
57432 buf[buf.length] = rt.apply(rp);
57434 return [lbuf.join(""), buf.join("")];
57437 renderBody : function(){
57438 var markup = this.renderRows();
57439 var bt = this.templates.body;
57440 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57444 * Refreshes the grid
57445 * @param {Boolean} headersToo
57447 refresh : function(headersToo){
57448 this.fireEvent("beforerefresh", this);
57449 this.grid.stopEditing();
57450 var result = this.renderBody();
57451 this.lockedBody.update(result[0]);
57452 this.mainBody.update(result[1]);
57453 if(headersToo === true){
57454 this.updateHeaders();
57455 this.updateColumns();
57456 this.updateSplitters();
57457 this.updateHeaderSortState();
57459 this.syncRowHeights();
57461 this.fireEvent("refresh", this);
57464 handleColumnMove : function(cm, oldIndex, newIndex){
57465 this.indexMap = null;
57466 var s = this.getScrollState();
57467 this.refresh(true);
57468 this.restoreScroll(s);
57469 this.afterMove(newIndex);
57472 afterMove : function(colIndex){
57473 if(this.enableMoveAnim && Roo.enableFx){
57474 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57476 // if multisort - fix sortOrder, and reload..
57477 if (this.grid.dataSource.multiSort) {
57478 // the we can call sort again..
57479 var dm = this.grid.dataSource;
57480 var cm = this.grid.colModel;
57482 for(var i = 0; i < cm.config.length; i++ ) {
57484 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57485 continue; // dont' bother, it's not in sort list or being set.
57488 so.push(cm.config[i].dataIndex);
57491 dm.load(dm.lastOptions);
57498 updateCell : function(dm, rowIndex, dataIndex){
57499 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57500 if(typeof colIndex == "undefined"){ // not present in grid
57503 var cm = this.grid.colModel;
57504 var cell = this.getCell(rowIndex, colIndex);
57505 var cellText = this.getCellText(rowIndex, colIndex);
57508 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57509 id : cm.getColumnId(colIndex),
57510 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57512 var renderer = cm.getRenderer(colIndex);
57513 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57514 if(typeof val == "undefined" || val === "") {
57517 cellText.innerHTML = val;
57518 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57519 this.syncRowHeights(rowIndex, rowIndex);
57522 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57524 if(this.grid.autoSizeHeaders){
57525 var h = this.getHeaderCellMeasure(colIndex);
57526 maxWidth = Math.max(maxWidth, h.scrollWidth);
57529 if(this.cm.isLocked(colIndex)){
57530 tb = this.getLockedTable();
57533 tb = this.getBodyTable();
57534 index = colIndex - this.cm.getLockedCount();
57537 var rows = tb.rows;
57538 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57539 for(var i = 0; i < stopIndex; i++){
57540 var cell = rows[i].childNodes[index].firstChild;
57541 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57544 return maxWidth + /*margin for error in IE*/ 5;
57547 * Autofit a column to its content.
57548 * @param {Number} colIndex
57549 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57551 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57552 if(this.cm.isHidden(colIndex)){
57553 return; // can't calc a hidden column
57556 var cid = this.cm.getColumnId(colIndex);
57557 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57558 if(this.grid.autoSizeHeaders){
57559 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57562 var newWidth = this.calcColumnWidth(colIndex);
57563 this.cm.setColumnWidth(colIndex,
57564 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57565 if(!suppressEvent){
57566 this.grid.fireEvent("columnresize", colIndex, newWidth);
57571 * Autofits all columns to their content and then expands to fit any extra space in the grid
57573 autoSizeColumns : function(){
57574 var cm = this.grid.colModel;
57575 var colCount = cm.getColumnCount();
57576 for(var i = 0; i < colCount; i++){
57577 this.autoSizeColumn(i, true, true);
57579 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57582 this.updateColumns();
57588 * Autofits all columns to the grid's width proportionate with their current size
57589 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57591 fitColumns : function(reserveScrollSpace){
57592 var cm = this.grid.colModel;
57593 var colCount = cm.getColumnCount();
57597 for (i = 0; i < colCount; i++){
57598 if(!cm.isHidden(i) && !cm.isFixed(i)){
57599 w = cm.getColumnWidth(i);
57605 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57606 if(reserveScrollSpace){
57609 var frac = (avail - cm.getTotalWidth())/width;
57610 while (cols.length){
57613 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57615 this.updateColumns();
57619 onRowSelect : function(rowIndex){
57620 var row = this.getRowComposite(rowIndex);
57621 row.addClass("x-grid-row-selected");
57624 onRowDeselect : function(rowIndex){
57625 var row = this.getRowComposite(rowIndex);
57626 row.removeClass("x-grid-row-selected");
57629 onCellSelect : function(row, col){
57630 var cell = this.getCell(row, col);
57632 Roo.fly(cell).addClass("x-grid-cell-selected");
57636 onCellDeselect : function(row, col){
57637 var cell = this.getCell(row, col);
57639 Roo.fly(cell).removeClass("x-grid-cell-selected");
57643 updateHeaderSortState : function(){
57645 // sort state can be single { field: xxx, direction : yyy}
57646 // or { xxx=>ASC , yyy : DESC ..... }
57649 if (!this.ds.multiSort) {
57650 var state = this.ds.getSortState();
57654 mstate[state.field] = state.direction;
57655 // FIXME... - this is not used here.. but might be elsewhere..
57656 this.sortState = state;
57659 mstate = this.ds.sortToggle;
57661 //remove existing sort classes..
57663 var sc = this.sortClasses;
57664 var hds = this.el.select(this.headerSelector).removeClass(sc);
57666 for(var f in mstate) {
57668 var sortColumn = this.cm.findColumnIndex(f);
57670 if(sortColumn != -1){
57671 var sortDir = mstate[f];
57672 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57681 handleHeaderClick : function(g, index,e){
57683 Roo.log("header click");
57686 // touch events on header are handled by context
57687 this.handleHdCtx(g,index,e);
57692 if(this.headersDisabled){
57695 var dm = g.dataSource, cm = g.colModel;
57696 if(!cm.isSortable(index)){
57701 if (dm.multiSort) {
57702 // update the sortOrder
57704 for(var i = 0; i < cm.config.length; i++ ) {
57706 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57707 continue; // dont' bother, it's not in sort list or being set.
57710 so.push(cm.config[i].dataIndex);
57716 dm.sort(cm.getDataIndex(index));
57720 destroy : function(){
57722 this.colMenu.removeAll();
57723 Roo.menu.MenuMgr.unregister(this.colMenu);
57724 this.colMenu.getEl().remove();
57725 delete this.colMenu;
57728 this.hmenu.removeAll();
57729 Roo.menu.MenuMgr.unregister(this.hmenu);
57730 this.hmenu.getEl().remove();
57733 if(this.grid.enableColumnMove){
57734 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57736 for(var dd in dds){
57737 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57738 var elid = dds[dd].dragElId;
57740 Roo.get(elid).remove();
57741 } else if(dds[dd].config.isTarget){
57742 dds[dd].proxyTop.remove();
57743 dds[dd].proxyBottom.remove();
57746 if(Roo.dd.DDM.locationCache[dd]){
57747 delete Roo.dd.DDM.locationCache[dd];
57750 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57753 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57754 this.bind(null, null);
57755 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57758 handleLockChange : function(){
57759 this.refresh(true);
57762 onDenyColumnLock : function(){
57766 onDenyColumnHide : function(){
57770 handleHdMenuClick : function(item){
57771 var index = this.hdCtxIndex;
57772 var cm = this.cm, ds = this.ds;
57775 ds.sort(cm.getDataIndex(index), "ASC");
57778 ds.sort(cm.getDataIndex(index), "DESC");
57781 var lc = cm.getLockedCount();
57782 if(cm.getColumnCount(true) <= lc+1){
57783 this.onDenyColumnLock();
57787 cm.setLocked(index, true, true);
57788 cm.moveColumn(index, lc);
57789 this.grid.fireEvent("columnmove", index, lc);
57791 cm.setLocked(index, true);
57795 var lc = cm.getLockedCount();
57796 if((lc-1) != index){
57797 cm.setLocked(index, false, true);
57798 cm.moveColumn(index, lc-1);
57799 this.grid.fireEvent("columnmove", index, lc-1);
57801 cm.setLocked(index, false);
57804 case 'wider': // used to expand cols on touch..
57806 var cw = cm.getColumnWidth(index);
57807 cw += (item.id == 'wider' ? 1 : -1) * 50;
57808 cw = Math.max(0, cw);
57809 cw = Math.min(cw,4000);
57810 cm.setColumnWidth(index, cw);
57814 index = cm.getIndexById(item.id.substr(4));
57816 if(item.checked && cm.getColumnCount(true) <= 1){
57817 this.onDenyColumnHide();
57820 cm.setHidden(index, item.checked);
57826 beforeColMenuShow : function(){
57827 var cm = this.cm, colCount = cm.getColumnCount();
57828 this.colMenu.removeAll();
57829 for(var i = 0; i < colCount; i++){
57830 this.colMenu.add(new Roo.menu.CheckItem({
57831 id: "col-"+cm.getColumnId(i),
57832 text: cm.getColumnHeader(i),
57833 checked: !cm.isHidden(i),
57839 handleHdCtx : function(g, index, e){
57841 var hd = this.getHeaderCell(index);
57842 this.hdCtxIndex = index;
57843 var ms = this.hmenu.items, cm = this.cm;
57844 ms.get("asc").setDisabled(!cm.isSortable(index));
57845 ms.get("desc").setDisabled(!cm.isSortable(index));
57846 if(this.grid.enableColLock !== false){
57847 ms.get("lock").setDisabled(cm.isLocked(index));
57848 ms.get("unlock").setDisabled(!cm.isLocked(index));
57850 this.hmenu.show(hd, "tl-bl");
57853 handleHdOver : function(e){
57854 var hd = this.findHeaderCell(e.getTarget());
57855 if(hd && !this.headersDisabled){
57856 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57857 this.fly(hd).addClass("x-grid-hd-over");
57862 handleHdOut : function(e){
57863 var hd = this.findHeaderCell(e.getTarget());
57865 this.fly(hd).removeClass("x-grid-hd-over");
57869 handleSplitDblClick : function(e, t){
57870 var i = this.getCellIndex(t);
57871 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57872 this.autoSizeColumn(i, true);
57877 render : function(){
57880 var colCount = cm.getColumnCount();
57882 if(this.grid.monitorWindowResize === true){
57883 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57885 var header = this.renderHeaders();
57886 var body = this.templates.body.apply({rows:""});
57887 var html = this.templates.master.apply({
57890 lockedHeader: header[0],
57894 //this.updateColumns();
57896 this.grid.getGridEl().dom.innerHTML = html;
57898 this.initElements();
57900 // a kludge to fix the random scolling effect in webkit
57901 this.el.on("scroll", function() {
57902 this.el.dom.scrollTop=0; // hopefully not recursive..
57905 this.scroller.on("scroll", this.handleScroll, this);
57906 this.lockedBody.on("mousewheel", this.handleWheel, this);
57907 this.mainBody.on("mousewheel", this.handleWheel, this);
57909 this.mainHd.on("mouseover", this.handleHdOver, this);
57910 this.mainHd.on("mouseout", this.handleHdOut, this);
57911 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57912 {delegate: "."+this.splitClass});
57914 this.lockedHd.on("mouseover", this.handleHdOver, this);
57915 this.lockedHd.on("mouseout", this.handleHdOut, this);
57916 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57917 {delegate: "."+this.splitClass});
57919 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57920 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57923 this.updateSplitters();
57925 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57926 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57927 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57930 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57931 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57933 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57934 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57936 if(this.grid.enableColLock !== false){
57937 this.hmenu.add('-',
57938 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57939 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57943 this.hmenu.add('-',
57944 {id:"wider", text: this.columnsWiderText},
57945 {id:"narrow", text: this.columnsNarrowText }
57951 if(this.grid.enableColumnHide !== false){
57953 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57954 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57955 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57957 this.hmenu.add('-',
57958 {id:"columns", text: this.columnsText, menu: this.colMenu}
57961 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57963 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57966 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57967 this.dd = new Roo.grid.GridDragZone(this.grid, {
57968 ddGroup : this.grid.ddGroup || 'GridDD'
57974 for(var i = 0; i < colCount; i++){
57975 if(cm.isHidden(i)){
57976 this.hideColumn(i);
57978 if(cm.config[i].align){
57979 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57980 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57984 this.updateHeaderSortState();
57986 this.beforeInitialResize();
57989 // two part rendering gives faster view to the user
57990 this.renderPhase2.defer(1, this);
57993 renderPhase2 : function(){
57994 // render the rows now
57996 if(this.grid.autoSizeColumns){
57997 this.autoSizeColumns();
58001 beforeInitialResize : function(){
58005 onColumnSplitterMoved : function(i, w){
58006 this.userResized = true;
58007 var cm = this.grid.colModel;
58008 cm.setColumnWidth(i, w, true);
58009 var cid = cm.getColumnId(i);
58010 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
58011 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
58012 this.updateSplitters();
58014 this.grid.fireEvent("columnresize", i, w);
58017 syncRowHeights : function(startIndex, endIndex){
58018 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
58019 startIndex = startIndex || 0;
58020 var mrows = this.getBodyTable().rows;
58021 var lrows = this.getLockedTable().rows;
58022 var len = mrows.length-1;
58023 endIndex = Math.min(endIndex || len, len);
58024 for(var i = startIndex; i <= endIndex; i++){
58025 var m = mrows[i], l = lrows[i];
58026 var h = Math.max(m.offsetHeight, l.offsetHeight);
58027 m.style.height = l.style.height = h + "px";
58032 layout : function(initialRender, is2ndPass)
58035 var auto = g.autoHeight;
58036 var scrollOffset = 16;
58037 var c = g.getGridEl(), cm = this.cm,
58038 expandCol = g.autoExpandColumn,
58040 //c.beginMeasure();
58042 if(!c.dom.offsetWidth){ // display:none?
58044 this.lockedWrap.show();
58045 this.mainWrap.show();
58050 var hasLock = this.cm.isLocked(0);
58052 var tbh = this.headerPanel.getHeight();
58053 var bbh = this.footerPanel.getHeight();
58056 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
58057 var newHeight = ch + c.getBorderWidth("tb");
58059 newHeight = Math.min(g.maxHeight, newHeight);
58061 c.setHeight(newHeight);
58065 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
58068 var s = this.scroller;
58070 var csize = c.getSize(true);
58072 this.el.setSize(csize.width, csize.height);
58074 this.headerPanel.setWidth(csize.width);
58075 this.footerPanel.setWidth(csize.width);
58077 var hdHeight = this.mainHd.getHeight();
58078 var vw = csize.width;
58079 var vh = csize.height - (tbh + bbh);
58083 var bt = this.getBodyTable();
58085 if(cm.getLockedCount() == cm.config.length){
58086 bt = this.getLockedTable();
58089 var ltWidth = hasLock ?
58090 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
58092 var scrollHeight = bt.offsetHeight;
58093 var scrollWidth = ltWidth + bt.offsetWidth;
58094 var vscroll = false, hscroll = false;
58096 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
58098 var lw = this.lockedWrap, mw = this.mainWrap;
58099 var lb = this.lockedBody, mb = this.mainBody;
58101 setTimeout(function(){
58102 var t = s.dom.offsetTop;
58103 var w = s.dom.clientWidth,
58104 h = s.dom.clientHeight;
58107 lw.setSize(ltWidth, h);
58109 mw.setLeftTop(ltWidth, t);
58110 mw.setSize(w-ltWidth, h);
58112 lb.setHeight(h-hdHeight);
58113 mb.setHeight(h-hdHeight);
58115 if(is2ndPass !== true && !gv.userResized && expandCol){
58116 // high speed resize without full column calculation
58118 var ci = cm.getIndexById(expandCol);
58120 ci = cm.findColumnIndex(expandCol);
58122 ci = Math.max(0, ci); // make sure it's got at least the first col.
58123 var expandId = cm.getColumnId(ci);
58124 var tw = cm.getTotalWidth(false);
58125 var currentWidth = cm.getColumnWidth(ci);
58126 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
58127 if(currentWidth != cw){
58128 cm.setColumnWidth(ci, cw, true);
58129 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
58130 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
58131 gv.updateSplitters();
58132 gv.layout(false, true);
58144 onWindowResize : function(){
58145 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
58151 appendFooter : function(parentEl){
58155 sortAscText : "Sort Ascending",
58156 sortDescText : "Sort Descending",
58157 lockText : "Lock Column",
58158 unlockText : "Unlock Column",
58159 columnsText : "Columns",
58161 columnsWiderText : "Wider",
58162 columnsNarrowText : "Thinner"
58166 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
58167 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
58168 this.proxy.el.addClass('x-grid3-col-dd');
58171 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
58172 handleMouseDown : function(e){
58176 callHandleMouseDown : function(e){
58177 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
58182 * Ext JS Library 1.1.1
58183 * Copyright(c) 2006-2007, Ext JS, LLC.
58185 * Originally Released Under LGPL - original licence link has changed is not relivant.
58188 * <script type="text/javascript">
58191 * @extends Roo.dd.DDProxy
58192 * @class Roo.grid.SplitDragZone
58193 * Support for Column Header resizing
58195 * @param {Object} config
58198 // This is a support class used internally by the Grid components
58199 Roo.grid.SplitDragZone = function(grid, hd, hd2){
58201 this.view = grid.getView();
58202 this.proxy = this.view.resizeProxy;
58203 Roo.grid.SplitDragZone.superclass.constructor.call(
58206 "gridSplitters" + this.grid.getGridEl().id, // SGROUP
58208 dragElId : Roo.id(this.proxy.dom),
58213 this.setHandleElId(Roo.id(hd));
58214 if (hd2 !== false) {
58215 this.setOuterHandleElId(Roo.id(hd2));
58218 this.scroll = false;
58220 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
58221 fly: Roo.Element.fly,
58223 b4StartDrag : function(x, y){
58224 this.view.headersDisabled = true;
58225 var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
58226 this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
58228 this.proxy.setHeight(h);
58230 // for old system colWidth really stored the actual width?
58231 // in bootstrap we tried using xs/ms/etc.. to do % sizing?
58232 // which in reality did not work.. - it worked only for fixed sizes
58233 // for resizable we need to use actual sizes.
58234 var w = this.cm.getColumnWidth(this.cellIndex);
58235 if (!this.view.mainWrap) {
58237 w = this.view.getHeaderIndex(this.cellIndex).getWidth();
58242 // this was w-this.grid.minColumnWidth;
58243 // doesnt really make sense? - w = thie curren width or the rendered one?
58244 var minw = Math.max(w-this.grid.minColumnWidth, 0);
58245 this.resetConstraints();
58246 this.setXConstraint(minw, 1000);
58247 this.setYConstraint(0, 0);
58248 this.minX = x - minw;
58249 this.maxX = x + 1000;
58251 if (!this.view.mainWrap) { // this is Bootstrap code..
58252 this.getDragEl().style.display='block';
58255 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
58259 handleMouseDown : function(e){
58260 ev = Roo.EventObject.setEvent(e);
58261 var t = this.fly(ev.getTarget());
58262 if(t.hasClass("x-grid-split")){
58263 this.cellIndex = this.view.getCellIndex(t.dom);
58264 this.split = t.dom;
58265 this.cm = this.grid.colModel;
58266 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
58267 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
58272 endDrag : function(e){
58273 this.view.headersDisabled = false;
58274 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
58275 var diff = endX - this.startPos;
58277 var w = this.cm.getColumnWidth(this.cellIndex);
58278 if (!this.view.mainWrap) {
58281 this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
58284 autoOffset : function(){
58285 this.setDelta(0,0);
58289 * Ext JS Library 1.1.1
58290 * Copyright(c) 2006-2007, Ext JS, LLC.
58292 * Originally Released Under LGPL - original licence link has changed is not relivant.
58295 * <script type="text/javascript">
58299 // This is a support class used internally by the Grid components
58300 Roo.grid.GridDragZone = function(grid, config){
58301 this.view = grid.getView();
58302 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
58303 if(this.view.lockedBody){
58304 this.setHandleElId(Roo.id(this.view.mainBody.dom));
58305 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
58307 this.scroll = false;
58309 this.ddel = document.createElement('div');
58310 this.ddel.className = 'x-grid-dd-wrap';
58313 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
58314 ddGroup : "GridDD",
58316 getDragData : function(e){
58317 var t = Roo.lib.Event.getTarget(e);
58318 var rowIndex = this.view.findRowIndex(t);
58319 var sm = this.grid.selModel;
58321 //Roo.log(rowIndex);
58323 if (sm.getSelectedCell) {
58324 // cell selection..
58325 if (!sm.getSelectedCell()) {
58328 if (rowIndex != sm.getSelectedCell()[0]) {
58333 if (sm.getSelections && sm.getSelections().length < 1) {
58338 // before it used to all dragging of unseleted... - now we dont do that.
58339 if(rowIndex !== false){
58344 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58346 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58349 if (e.hasModifier()){
58350 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58353 Roo.log("getDragData");
58358 rowIndex: rowIndex,
58359 selections: sm.getSelections ? sm.getSelections() : (
58360 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
58367 onInitDrag : function(e){
58368 var data = this.dragData;
58369 this.ddel.innerHTML = this.grid.getDragDropText();
58370 this.proxy.update(this.ddel);
58371 // fire start drag?
58374 afterRepair : function(){
58375 this.dragging = false;
58378 getRepairXY : function(e, data){
58382 onEndDrag : function(data, e){
58386 onValidDrop : function(dd, e, id){
58391 beforeInvalidDrop : function(e, id){
58396 * Ext JS Library 1.1.1
58397 * Copyright(c) 2006-2007, Ext JS, LLC.
58399 * Originally Released Under LGPL - original licence link has changed is not relivant.
58402 * <script type="text/javascript">
58407 * @class Roo.grid.ColumnModel
58408 * @extends Roo.util.Observable
58409 * This is the default implementation of a ColumnModel used by the Grid. It defines
58410 * the columns in the grid.
58413 var colModel = new Roo.grid.ColumnModel([
58414 {header: "Ticker", width: 60, sortable: true, locked: true},
58415 {header: "Company Name", width: 150, sortable: true},
58416 {header: "Market Cap.", width: 100, sortable: true},
58417 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58418 {header: "Employees", width: 100, sortable: true, resizable: false}
58423 * The config options listed for this class are options which may appear in each
58424 * individual column definition.
58425 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58427 * @param {Object} config An Array of column config objects. See this class's
58428 * config objects for details.
58430 Roo.grid.ColumnModel = function(config){
58432 * The config passed into the constructor
58434 this.config = []; //config;
58437 // if no id, create one
58438 // if the column does not have a dataIndex mapping,
58439 // map it to the order it is in the config
58440 for(var i = 0, len = config.length; i < len; i++){
58441 this.addColumn(config[i]);
58446 * The width of columns which have no width specified (defaults to 100)
58449 this.defaultWidth = 100;
58452 * Default sortable of columns which have no sortable specified (defaults to false)
58455 this.defaultSortable = false;
58459 * @event widthchange
58460 * Fires when the width of a column changes.
58461 * @param {ColumnModel} this
58462 * @param {Number} columnIndex The column index
58463 * @param {Number} newWidth The new width
58465 "widthchange": true,
58467 * @event headerchange
58468 * Fires when the text of a header changes.
58469 * @param {ColumnModel} this
58470 * @param {Number} columnIndex The column index
58471 * @param {Number} newText The new header text
58473 "headerchange": true,
58475 * @event hiddenchange
58476 * Fires when a column is hidden or "unhidden".
58477 * @param {ColumnModel} this
58478 * @param {Number} columnIndex The column index
58479 * @param {Boolean} hidden true if hidden, false otherwise
58481 "hiddenchange": true,
58483 * @event columnmoved
58484 * Fires when a column is moved.
58485 * @param {ColumnModel} this
58486 * @param {Number} oldIndex
58487 * @param {Number} newIndex
58489 "columnmoved" : true,
58491 * @event columlockchange
58492 * Fires when a column's locked state is changed
58493 * @param {ColumnModel} this
58494 * @param {Number} colIndex
58495 * @param {Boolean} locked true if locked
58497 "columnlockchange" : true
58499 Roo.grid.ColumnModel.superclass.constructor.call(this);
58501 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58503 * @cfg {String} header The header text to display in the Grid view.
58506 * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
58509 * @cfg {String} smHeader Header at Bootsrap Small width
58512 * @cfg {String} mdHeader Header at Bootsrap Medium width
58515 * @cfg {String} lgHeader Header at Bootsrap Large width
58518 * @cfg {String} xlHeader Header at Bootsrap extra Large width
58521 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58522 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58523 * specified, the column's index is used as an index into the Record's data Array.
58526 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58527 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58530 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58531 * Defaults to the value of the {@link #defaultSortable} property.
58532 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58535 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58538 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58541 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58544 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58547 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58548 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58549 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58550 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58553 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58556 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58559 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58562 * @cfg {String} cursor (Optional)
58565 * @cfg {String} tooltip (Optional)
58568 * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
58571 * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
58574 * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
58577 * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
58580 * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
58583 * Returns the id of the column at the specified index.
58584 * @param {Number} index The column index
58585 * @return {String} the id
58587 getColumnId : function(index){
58588 return this.config[index].id;
58592 * Returns the column for a specified id.
58593 * @param {String} id The column id
58594 * @return {Object} the column
58596 getColumnById : function(id){
58597 return this.lookup[id];
58602 * Returns the column Object for a specified dataIndex.
58603 * @param {String} dataIndex The column dataIndex
58604 * @return {Object|Boolean} the column or false if not found
58606 getColumnByDataIndex: function(dataIndex){
58607 var index = this.findColumnIndex(dataIndex);
58608 return index > -1 ? this.config[index] : false;
58612 * Returns the index for a specified column id.
58613 * @param {String} id The column id
58614 * @return {Number} the index, or -1 if not found
58616 getIndexById : function(id){
58617 for(var i = 0, len = this.config.length; i < len; i++){
58618 if(this.config[i].id == id){
58626 * Returns the index for a specified column dataIndex.
58627 * @param {String} dataIndex The column dataIndex
58628 * @return {Number} the index, or -1 if not found
58631 findColumnIndex : function(dataIndex){
58632 for(var i = 0, len = this.config.length; i < len; i++){
58633 if(this.config[i].dataIndex == dataIndex){
58641 moveColumn : function(oldIndex, newIndex){
58642 var c = this.config[oldIndex];
58643 this.config.splice(oldIndex, 1);
58644 this.config.splice(newIndex, 0, c);
58645 this.dataMap = null;
58646 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58649 isLocked : function(colIndex){
58650 return this.config[colIndex].locked === true;
58653 setLocked : function(colIndex, value, suppressEvent){
58654 if(this.isLocked(colIndex) == value){
58657 this.config[colIndex].locked = value;
58658 if(!suppressEvent){
58659 this.fireEvent("columnlockchange", this, colIndex, value);
58663 getTotalLockedWidth : function(){
58664 var totalWidth = 0;
58665 for(var i = 0; i < this.config.length; i++){
58666 if(this.isLocked(i) && !this.isHidden(i)){
58667 this.totalWidth += this.getColumnWidth(i);
58673 getLockedCount : function(){
58674 for(var i = 0, len = this.config.length; i < len; i++){
58675 if(!this.isLocked(i)){
58680 return this.config.length;
58684 * Returns the number of columns.
58687 getColumnCount : function(visibleOnly){
58688 if(visibleOnly === true){
58690 for(var i = 0, len = this.config.length; i < len; i++){
58691 if(!this.isHidden(i)){
58697 return this.config.length;
58701 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58702 * @param {Function} fn
58703 * @param {Object} scope (optional)
58704 * @return {Array} result
58706 getColumnsBy : function(fn, scope){
58708 for(var i = 0, len = this.config.length; i < len; i++){
58709 var c = this.config[i];
58710 if(fn.call(scope||this, c, i) === true){
58718 * Returns true if the specified column is sortable.
58719 * @param {Number} col The column index
58720 * @return {Boolean}
58722 isSortable : function(col){
58723 if(typeof this.config[col].sortable == "undefined"){
58724 return this.defaultSortable;
58726 return this.config[col].sortable;
58730 * Returns the rendering (formatting) function defined for the column.
58731 * @param {Number} col The column index.
58732 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58734 getRenderer : function(col){
58735 if(!this.config[col].renderer){
58736 return Roo.grid.ColumnModel.defaultRenderer;
58738 return this.config[col].renderer;
58742 * Sets the rendering (formatting) function for a column.
58743 * @param {Number} col The column index
58744 * @param {Function} fn The function to use to process the cell's raw data
58745 * to return HTML markup for the grid view. The render function is called with
58746 * the following parameters:<ul>
58747 * <li>Data value.</li>
58748 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58749 * <li>css A CSS style string to apply to the table cell.</li>
58750 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58751 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58752 * <li>Row index</li>
58753 * <li>Column index</li>
58754 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58756 setRenderer : function(col, fn){
58757 this.config[col].renderer = fn;
58761 * Returns the width for the specified column.
58762 * @param {Number} col The column index
58763 * @param (optional) {String} gridSize bootstrap width size.
58766 getColumnWidth : function(col, gridSize)
58768 var cfg = this.config[col];
58770 if (typeof(gridSize) == 'undefined') {
58771 return cfg.width * 1 || this.defaultWidth;
58773 if (gridSize === false) { // if we set it..
58774 return cfg.width || false;
58776 var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
58778 for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
58779 if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
58782 return cfg[ sizes[i] ];
58789 * Sets the width for a column.
58790 * @param {Number} col The column index
58791 * @param {Number} width The new width
58793 setColumnWidth : function(col, width, suppressEvent){
58794 this.config[col].width = width;
58795 this.totalWidth = null;
58796 if(!suppressEvent){
58797 this.fireEvent("widthchange", this, col, width);
58802 * Returns the total width of all columns.
58803 * @param {Boolean} includeHidden True to include hidden column widths
58806 getTotalWidth : function(includeHidden){
58807 if(!this.totalWidth){
58808 this.totalWidth = 0;
58809 for(var i = 0, len = this.config.length; i < len; i++){
58810 if(includeHidden || !this.isHidden(i)){
58811 this.totalWidth += this.getColumnWidth(i);
58815 return this.totalWidth;
58819 * Returns the header for the specified column.
58820 * @param {Number} col The column index
58823 getColumnHeader : function(col){
58824 return this.config[col].header;
58828 * Sets the header for a column.
58829 * @param {Number} col The column index
58830 * @param {String} header The new header
58832 setColumnHeader : function(col, header){
58833 this.config[col].header = header;
58834 this.fireEvent("headerchange", this, col, header);
58838 * Returns the tooltip for the specified column.
58839 * @param {Number} col The column index
58842 getColumnTooltip : function(col){
58843 return this.config[col].tooltip;
58846 * Sets the tooltip for a column.
58847 * @param {Number} col The column index
58848 * @param {String} tooltip The new tooltip
58850 setColumnTooltip : function(col, tooltip){
58851 this.config[col].tooltip = tooltip;
58855 * Returns the dataIndex for the specified column.
58856 * @param {Number} col The column index
58859 getDataIndex : function(col){
58860 return this.config[col].dataIndex;
58864 * Sets the dataIndex for a column.
58865 * @param {Number} col The column index
58866 * @param {Number} dataIndex The new dataIndex
58868 setDataIndex : function(col, dataIndex){
58869 this.config[col].dataIndex = dataIndex;
58875 * Returns true if the cell is editable.
58876 * @param {Number} colIndex The column index
58877 * @param {Number} rowIndex The row index - this is nto actually used..?
58878 * @return {Boolean}
58880 isCellEditable : function(colIndex, rowIndex){
58881 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58885 * Returns the editor defined for the cell/column.
58886 * return false or null to disable editing.
58887 * @param {Number} colIndex The column index
58888 * @param {Number} rowIndex The row index
58891 getCellEditor : function(colIndex, rowIndex){
58892 return this.config[colIndex].editor;
58896 * Sets if a column is editable.
58897 * @param {Number} col The column index
58898 * @param {Boolean} editable True if the column is editable
58900 setEditable : function(col, editable){
58901 this.config[col].editable = editable;
58906 * Returns true if the column is hidden.
58907 * @param {Number} colIndex The column index
58908 * @return {Boolean}
58910 isHidden : function(colIndex){
58911 return this.config[colIndex].hidden;
58916 * Returns true if the column width cannot be changed
58918 isFixed : function(colIndex){
58919 return this.config[colIndex].fixed;
58923 * Returns true if the column can be resized
58924 * @return {Boolean}
58926 isResizable : function(colIndex){
58927 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58930 * Sets if a column is hidden.
58931 * @param {Number} colIndex The column index
58932 * @param {Boolean} hidden True if the column is hidden
58934 setHidden : function(colIndex, hidden){
58935 this.config[colIndex].hidden = hidden;
58936 this.totalWidth = null;
58937 this.fireEvent("hiddenchange", this, colIndex, hidden);
58941 * Sets the editor for a column.
58942 * @param {Number} col The column index
58943 * @param {Object} editor The editor object
58945 setEditor : function(col, editor){
58946 this.config[col].editor = editor;
58949 * Add a column (experimental...) - defaults to adding to the end..
58950 * @param {Object} config
58952 addColumn : function(c)
58955 var i = this.config.length;
58956 this.config[i] = c;
58958 if(typeof c.dataIndex == "undefined"){
58961 if(typeof c.renderer == "string"){
58962 c.renderer = Roo.util.Format[c.renderer];
58964 if(typeof c.id == "undefined"){
58967 if(c.editor && c.editor.xtype){
58968 c.editor = Roo.factory(c.editor, Roo.grid);
58970 if(c.editor && c.editor.isFormField){
58971 c.editor = new Roo.grid.GridEditor(c.editor);
58973 this.lookup[c.id] = c;
58978 Roo.grid.ColumnModel.defaultRenderer = function(value)
58980 if(typeof value == "object") {
58983 if(typeof value == "string" && value.length < 1){
58987 return String.format("{0}", value);
58990 // Alias for backwards compatibility
58991 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
58994 * Ext JS Library 1.1.1
58995 * Copyright(c) 2006-2007, Ext JS, LLC.
58997 * Originally Released Under LGPL - original licence link has changed is not relivant.
59000 * <script type="text/javascript">
59004 * @class Roo.grid.AbstractSelectionModel
59005 * @extends Roo.util.Observable
59007 * Abstract base class for grid SelectionModels. It provides the interface that should be
59008 * implemented by descendant classes. This class should not be directly instantiated.
59011 Roo.grid.AbstractSelectionModel = function(){
59012 this.locked = false;
59013 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
59016 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
59017 /** @ignore Called by the grid automatically. Do not call directly. */
59018 init : function(grid){
59024 * Locks the selections.
59027 this.locked = true;
59031 * Unlocks the selections.
59033 unlock : function(){
59034 this.locked = false;
59038 * Returns true if the selections are locked.
59039 * @return {Boolean}
59041 isLocked : function(){
59042 return this.locked;
59046 * Ext JS Library 1.1.1
59047 * Copyright(c) 2006-2007, Ext JS, LLC.
59049 * Originally Released Under LGPL - original licence link has changed is not relivant.
59052 * <script type="text/javascript">
59055 * @extends Roo.grid.AbstractSelectionModel
59056 * @class Roo.grid.RowSelectionModel
59057 * The default SelectionModel used by {@link Roo.grid.Grid}.
59058 * It supports multiple selections and keyboard selection/navigation.
59060 * @param {Object} config
59062 Roo.grid.RowSelectionModel = function(config){
59063 Roo.apply(this, config);
59064 this.selections = new Roo.util.MixedCollection(false, function(o){
59069 this.lastActive = false;
59073 * @event selectionchange
59074 * Fires when the selection changes
59075 * @param {SelectionModel} this
59077 "selectionchange" : true,
59079 * @event afterselectionchange
59080 * Fires after the selection changes (eg. by key press or clicking)
59081 * @param {SelectionModel} this
59083 "afterselectionchange" : true,
59085 * @event beforerowselect
59086 * Fires when a row is selected being selected, return false to cancel.
59087 * @param {SelectionModel} this
59088 * @param {Number} rowIndex The selected index
59089 * @param {Boolean} keepExisting False if other selections will be cleared
59091 "beforerowselect" : true,
59094 * Fires when a row is selected.
59095 * @param {SelectionModel} this
59096 * @param {Number} rowIndex The selected index
59097 * @param {Roo.data.Record} r The record
59099 "rowselect" : true,
59101 * @event rowdeselect
59102 * Fires when a row is deselected.
59103 * @param {SelectionModel} this
59104 * @param {Number} rowIndex The selected index
59106 "rowdeselect" : true
59108 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
59109 this.locked = false;
59112 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
59114 * @cfg {Boolean} singleSelect
59115 * True to allow selection of only one row at a time (defaults to false)
59117 singleSelect : false,
59120 initEvents : function(){
59122 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
59123 this.grid.on("mousedown", this.handleMouseDown, this);
59124 }else{ // allow click to work like normal
59125 this.grid.on("rowclick", this.handleDragableRowClick, this);
59127 // bootstrap does not have a view..
59128 var view = this.grid.view ? this.grid.view : this.grid;
59129 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
59130 "up" : function(e){
59132 this.selectPrevious(e.shiftKey);
59133 }else if(this.last !== false && this.lastActive !== false){
59134 var last = this.last;
59135 this.selectRange(this.last, this.lastActive-1);
59136 view.focusRow(this.lastActive);
59137 if(last !== false){
59141 this.selectFirstRow();
59143 this.fireEvent("afterselectionchange", this);
59145 "down" : function(e){
59147 this.selectNext(e.shiftKey);
59148 }else if(this.last !== false && this.lastActive !== false){
59149 var last = this.last;
59150 this.selectRange(this.last, this.lastActive+1);
59151 view.focusRow(this.lastActive);
59152 if(last !== false){
59156 this.selectFirstRow();
59158 this.fireEvent("afterselectionchange", this);
59164 view.on("refresh", this.onRefresh, this);
59165 view.on("rowupdated", this.onRowUpdated, this);
59166 view.on("rowremoved", this.onRemove, this);
59170 onRefresh : function(){
59171 var ds = this.grid.ds, i, v = this.grid.view;
59172 var s = this.selections;
59173 s.each(function(r){
59174 if((i = ds.indexOfId(r.id)) != -1){
59176 s.add(ds.getAt(i)); // updating the selection relate data
59184 onRemove : function(v, index, r){
59185 this.selections.remove(r);
59189 onRowUpdated : function(v, index, r){
59190 if(this.isSelected(r)){
59191 v.onRowSelect(index);
59197 * @param {Array} records The records to select
59198 * @param {Boolean} keepExisting (optional) True to keep existing selections
59200 selectRecords : function(records, keepExisting){
59202 this.clearSelections();
59204 var ds = this.grid.ds;
59205 for(var i = 0, len = records.length; i < len; i++){
59206 this.selectRow(ds.indexOf(records[i]), true);
59211 * Gets the number of selected rows.
59214 getCount : function(){
59215 return this.selections.length;
59219 * Selects the first row in the grid.
59221 selectFirstRow : function(){
59226 * Select the last row.
59227 * @param {Boolean} keepExisting (optional) True to keep existing selections
59229 selectLastRow : function(keepExisting){
59230 this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
59234 * Selects the row immediately following the last selected row.
59235 * @param {Boolean} keepExisting (optional) True to keep existing selections
59237 selectNext : function(keepExisting){
59238 if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
59239 this.selectRow(this.last+1, keepExisting);
59240 var view = this.grid.view ? this.grid.view : this.grid;
59241 view.focusRow(this.last);
59246 * Selects the row that precedes the last selected row.
59247 * @param {Boolean} keepExisting (optional) True to keep existing selections
59249 selectPrevious : function(keepExisting){
59251 this.selectRow(this.last-1, keepExisting);
59252 var view = this.grid.view ? this.grid.view : this.grid;
59253 view.focusRow(this.last);
59258 * Returns the selected records
59259 * @return {Array} Array of selected records
59261 getSelections : function(){
59262 return [].concat(this.selections.items);
59266 * Returns the first selected record.
59269 getSelected : function(){
59270 return this.selections.itemAt(0);
59275 * Clears all selections.
59277 clearSelections : function(fast){
59282 var ds = this.grid.ds;
59283 var s = this.selections;
59284 s.each(function(r){
59285 this.deselectRow(ds.indexOfId(r.id));
59289 this.selections.clear();
59296 * Selects all rows.
59298 selectAll : function(){
59302 this.selections.clear();
59303 for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
59304 this.selectRow(i, true);
59309 * Returns True if there is a selection.
59310 * @return {Boolean}
59312 hasSelection : function(){
59313 return this.selections.length > 0;
59317 * Returns True if the specified row is selected.
59318 * @param {Number/Record} record The record or index of the record to check
59319 * @return {Boolean}
59321 isSelected : function(index){
59322 var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
59323 return (r && this.selections.key(r.id) ? true : false);
59327 * Returns True if the specified record id is selected.
59328 * @param {String} id The id of record to check
59329 * @return {Boolean}
59331 isIdSelected : function(id){
59332 return (this.selections.key(id) ? true : false);
59336 handleMouseDown : function(e, t)
59338 var view = this.grid.view ? this.grid.view : this.grid;
59340 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
59343 if(e.shiftKey && this.last !== false){
59344 var last = this.last;
59345 this.selectRange(last, rowIndex, e.ctrlKey);
59346 this.last = last; // reset the last
59347 view.focusRow(rowIndex);
59349 var isSelected = this.isSelected(rowIndex);
59350 if(e.button !== 0 && isSelected){
59351 view.focusRow(rowIndex);
59352 }else if(e.ctrlKey && isSelected){
59353 this.deselectRow(rowIndex);
59354 }else if(!isSelected){
59355 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
59356 view.focusRow(rowIndex);
59359 this.fireEvent("afterselectionchange", this);
59362 handleDragableRowClick : function(grid, rowIndex, e)
59364 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
59365 this.selectRow(rowIndex, false);
59366 var view = this.grid.view ? this.grid.view : this.grid;
59367 view.focusRow(rowIndex);
59368 this.fireEvent("afterselectionchange", this);
59373 * Selects multiple rows.
59374 * @param {Array} rows Array of the indexes of the row to select
59375 * @param {Boolean} keepExisting (optional) True to keep existing selections
59377 selectRows : function(rows, keepExisting){
59379 this.clearSelections();
59381 for(var i = 0, len = rows.length; i < len; i++){
59382 this.selectRow(rows[i], true);
59387 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59388 * @param {Number} startRow The index of the first row in the range
59389 * @param {Number} endRow The index of the last row in the range
59390 * @param {Boolean} keepExisting (optional) True to retain existing selections
59392 selectRange : function(startRow, endRow, keepExisting){
59397 this.clearSelections();
59399 if(startRow <= endRow){
59400 for(var i = startRow; i <= endRow; i++){
59401 this.selectRow(i, true);
59404 for(var i = startRow; i >= endRow; i--){
59405 this.selectRow(i, true);
59411 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59412 * @param {Number} startRow The index of the first row in the range
59413 * @param {Number} endRow The index of the last row in the range
59415 deselectRange : function(startRow, endRow, preventViewNotify){
59419 for(var i = startRow; i <= endRow; i++){
59420 this.deselectRow(i, preventViewNotify);
59426 * @param {Number} row The index of the row to select
59427 * @param {Boolean} keepExisting (optional) True to keep existing selections
59429 selectRow : function(index, keepExisting, preventViewNotify){
59430 if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
59433 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59434 if(!keepExisting || this.singleSelect){
59435 this.clearSelections();
59437 var r = this.grid.ds.getAt(index);
59438 this.selections.add(r);
59439 this.last = this.lastActive = index;
59440 if(!preventViewNotify){
59441 var view = this.grid.view ? this.grid.view : this.grid;
59442 view.onRowSelect(index);
59444 this.fireEvent("rowselect", this, index, r);
59445 this.fireEvent("selectionchange", this);
59451 * @param {Number} row The index of the row to deselect
59453 deselectRow : function(index, preventViewNotify){
59457 if(this.last == index){
59460 if(this.lastActive == index){
59461 this.lastActive = false;
59463 var r = this.grid.ds.getAt(index);
59464 this.selections.remove(r);
59465 if(!preventViewNotify){
59466 var view = this.grid.view ? this.grid.view : this.grid;
59467 view.onRowDeselect(index);
59469 this.fireEvent("rowdeselect", this, index);
59470 this.fireEvent("selectionchange", this);
59474 restoreLast : function(){
59476 this.last = this._last;
59481 acceptsNav : function(row, col, cm){
59482 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59486 onEditorKey : function(field, e){
59487 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59492 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59494 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59496 }else if(k == e.ENTER && !e.ctrlKey){
59500 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59502 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59504 }else if(k == e.ESC){
59508 g.startEditing(newCell[0], newCell[1]);
59513 * Ext JS Library 1.1.1
59514 * Copyright(c) 2006-2007, Ext JS, LLC.
59516 * Originally Released Under LGPL - original licence link has changed is not relivant.
59519 * <script type="text/javascript">
59522 * @class Roo.grid.CellSelectionModel
59523 * @extends Roo.grid.AbstractSelectionModel
59524 * This class provides the basic implementation for cell selection in a grid.
59526 * @param {Object} config The object containing the configuration of this model.
59527 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59529 Roo.grid.CellSelectionModel = function(config){
59530 Roo.apply(this, config);
59532 this.selection = null;
59536 * @event beforerowselect
59537 * Fires before a cell is selected.
59538 * @param {SelectionModel} this
59539 * @param {Number} rowIndex The selected row index
59540 * @param {Number} colIndex The selected cell index
59542 "beforecellselect" : true,
59544 * @event cellselect
59545 * Fires when a cell is selected.
59546 * @param {SelectionModel} this
59547 * @param {Number} rowIndex The selected row index
59548 * @param {Number} colIndex The selected cell index
59550 "cellselect" : true,
59552 * @event selectionchange
59553 * Fires when the active selection changes.
59554 * @param {SelectionModel} this
59555 * @param {Object} selection null for no selection or an object (o) with two properties
59557 <li>o.record: the record object for the row the selection is in</li>
59558 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59561 "selectionchange" : true,
59564 * Fires when the tab (or enter) was pressed on the last editable cell
59565 * You can use this to trigger add new row.
59566 * @param {SelectionModel} this
59570 * @event beforeeditnext
59571 * Fires before the next editable sell is made active
59572 * You can use this to skip to another cell or fire the tabend
59573 * if you set cell to false
59574 * @param {Object} eventdata object : { cell : [ row, col ] }
59576 "beforeeditnext" : true
59578 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59581 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59583 enter_is_tab: false,
59586 initEvents : function(){
59587 this.grid.on("mousedown", this.handleMouseDown, this);
59588 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59589 var view = this.grid.view;
59590 view.on("refresh", this.onViewChange, this);
59591 view.on("rowupdated", this.onRowUpdated, this);
59592 view.on("beforerowremoved", this.clearSelections, this);
59593 view.on("beforerowsinserted", this.clearSelections, this);
59594 if(this.grid.isEditor){
59595 this.grid.on("beforeedit", this.beforeEdit, this);
59600 beforeEdit : function(e){
59601 this.select(e.row, e.column, false, true, e.record);
59605 onRowUpdated : function(v, index, r){
59606 if(this.selection && this.selection.record == r){
59607 v.onCellSelect(index, this.selection.cell[1]);
59612 onViewChange : function(){
59613 this.clearSelections(true);
59617 * Returns the currently selected cell,.
59618 * @return {Array} The selected cell (row, column) or null if none selected.
59620 getSelectedCell : function(){
59621 return this.selection ? this.selection.cell : null;
59625 * Clears all selections.
59626 * @param {Boolean} true to prevent the gridview from being notified about the change.
59628 clearSelections : function(preventNotify){
59629 var s = this.selection;
59631 if(preventNotify !== true){
59632 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59634 this.selection = null;
59635 this.fireEvent("selectionchange", this, null);
59640 * Returns true if there is a selection.
59641 * @return {Boolean}
59643 hasSelection : function(){
59644 return this.selection ? true : false;
59648 handleMouseDown : function(e, t){
59649 var v = this.grid.getView();
59650 if(this.isLocked()){
59653 var row = v.findRowIndex(t);
59654 var cell = v.findCellIndex(t);
59655 if(row !== false && cell !== false){
59656 this.select(row, cell);
59662 * @param {Number} rowIndex
59663 * @param {Number} collIndex
59665 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59666 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59667 this.clearSelections();
59668 r = r || this.grid.dataSource.getAt(rowIndex);
59671 cell : [rowIndex, colIndex]
59673 if(!preventViewNotify){
59674 var v = this.grid.getView();
59675 v.onCellSelect(rowIndex, colIndex);
59676 if(preventFocus !== true){
59677 v.focusCell(rowIndex, colIndex);
59680 this.fireEvent("cellselect", this, rowIndex, colIndex);
59681 this.fireEvent("selectionchange", this, this.selection);
59686 isSelectable : function(rowIndex, colIndex, cm){
59687 return !cm.isHidden(colIndex);
59691 handleKeyDown : function(e){
59692 //Roo.log('Cell Sel Model handleKeyDown');
59693 if(!e.isNavKeyPress()){
59696 var g = this.grid, s = this.selection;
59699 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59701 this.select(cell[0], cell[1]);
59706 var walk = function(row, col, step){
59707 return g.walkCells(row, col, step, sm.isSelectable, sm);
59709 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59716 // handled by onEditorKey
59717 if (g.isEditor && g.editing) {
59721 newCell = walk(r, c-1, -1);
59723 newCell = walk(r, c+1, 1);
59728 newCell = walk(r+1, c, 1);
59732 newCell = walk(r-1, c, -1);
59736 newCell = walk(r, c+1, 1);
59740 newCell = walk(r, c-1, -1);
59745 if(g.isEditor && !g.editing){
59746 g.startEditing(r, c);
59755 this.select(newCell[0], newCell[1]);
59761 acceptsNav : function(row, col, cm){
59762 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59766 * @param {Number} field (not used) - as it's normally used as a listener
59767 * @param {Number} e - event - fake it by using
59769 * var e = Roo.EventObjectImpl.prototype;
59770 * e.keyCode = e.TAB
59774 onEditorKey : function(field, e){
59776 var k = e.getKey(),
59779 ed = g.activeEditor,
59781 ///Roo.log('onEditorKey' + k);
59784 if (this.enter_is_tab && k == e.ENTER) {
59790 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59792 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59798 } else if(k == e.ENTER && !e.ctrlKey){
59801 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59803 } else if(k == e.ESC){
59808 var ecall = { cell : newCell, forward : forward };
59809 this.fireEvent('beforeeditnext', ecall );
59810 newCell = ecall.cell;
59811 forward = ecall.forward;
59815 //Roo.log('next cell after edit');
59816 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59817 } else if (forward) {
59818 // tabbed past last
59819 this.fireEvent.defer(100, this, ['tabend',this]);
59824 * Ext JS Library 1.1.1
59825 * Copyright(c) 2006-2007, Ext JS, LLC.
59827 * Originally Released Under LGPL - original licence link has changed is not relivant.
59830 * <script type="text/javascript">
59834 * @class Roo.grid.EditorGrid
59835 * @extends Roo.grid.Grid
59836 * Class for creating and editable grid.
59837 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59838 * The container MUST have some type of size defined for the grid to fill. The container will be
59839 * automatically set to position relative if it isn't already.
59840 * @param {Object} dataSource The data model to bind to
59841 * @param {Object} colModel The column model with info about this grid's columns
59843 Roo.grid.EditorGrid = function(container, config){
59844 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59845 this.getGridEl().addClass("xedit-grid");
59847 if(!this.selModel){
59848 this.selModel = new Roo.grid.CellSelectionModel();
59851 this.activeEditor = null;
59855 * @event beforeedit
59856 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59857 * <ul style="padding:5px;padding-left:16px;">
59858 * <li>grid - This grid</li>
59859 * <li>record - The record being edited</li>
59860 * <li>field - The field name being edited</li>
59861 * <li>value - The value for the field being edited.</li>
59862 * <li>row - The grid row index</li>
59863 * <li>column - The grid column index</li>
59864 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59866 * @param {Object} e An edit event (see above for description)
59868 "beforeedit" : true,
59871 * Fires after a cell is edited. <br />
59872 * <ul style="padding:5px;padding-left:16px;">
59873 * <li>grid - This grid</li>
59874 * <li>record - The record being edited</li>
59875 * <li>field - The field name being edited</li>
59876 * <li>value - The value being set</li>
59877 * <li>originalValue - The original value for the field, before the edit.</li>
59878 * <li>row - The grid row index</li>
59879 * <li>column - The grid column index</li>
59881 * @param {Object} e An edit event (see above for description)
59883 "afteredit" : true,
59885 * @event validateedit
59886 * Fires after a cell is edited, but before the value is set in the record.
59887 * You can use this to modify the value being set in the field, Return false
59888 * to cancel the change. The edit event object has the following properties <br />
59889 * <ul style="padding:5px;padding-left:16px;">
59890 * <li>editor - This editor</li>
59891 * <li>grid - This grid</li>
59892 * <li>record - The record being edited</li>
59893 * <li>field - The field name being edited</li>
59894 * <li>value - The value being set</li>
59895 * <li>originalValue - The original value for the field, before the edit.</li>
59896 * <li>row - The grid row index</li>
59897 * <li>column - The grid column index</li>
59898 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59900 * @param {Object} e An edit event (see above for description)
59902 "validateedit" : true
59904 this.on("bodyscroll", this.stopEditing, this);
59905 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59908 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59910 * @cfg {Number} clicksToEdit
59911 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59918 trackMouseOver: false, // causes very odd FF errors
59920 onCellDblClick : function(g, row, col){
59921 this.startEditing(row, col);
59924 onEditComplete : function(ed, value, startValue){
59925 this.editing = false;
59926 this.activeEditor = null;
59927 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59929 var field = this.colModel.getDataIndex(ed.col);
59934 originalValue: startValue,
59941 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59944 if(String(value) !== String(startValue)){
59946 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59947 r.set(field, e.value);
59948 // if we are dealing with a combo box..
59949 // then we also set the 'name' colum to be the displayField
59950 if (ed.field.displayField && ed.field.name) {
59951 r.set(ed.field.name, ed.field.el.dom.value);
59954 delete e.cancel; //?? why!!!
59955 this.fireEvent("afteredit", e);
59958 this.fireEvent("afteredit", e); // always fire it!
59960 this.view.focusCell(ed.row, ed.col);
59964 * Starts editing the specified for the specified row/column
59965 * @param {Number} rowIndex
59966 * @param {Number} colIndex
59968 startEditing : function(row, col){
59969 this.stopEditing();
59970 if(this.colModel.isCellEditable(col, row)){
59971 this.view.ensureVisible(row, col, true);
59973 var r = this.dataSource.getAt(row);
59974 var field = this.colModel.getDataIndex(col);
59975 var cell = Roo.get(this.view.getCell(row,col));
59980 value: r.data[field],
59985 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59986 this.editing = true;
59987 var ed = this.colModel.getCellEditor(col, row);
59993 ed.render(ed.parentEl || document.body);
59999 (function(){ // complex but required for focus issues in safari, ie and opera
60003 ed.on("complete", this.onEditComplete, this, {single: true});
60004 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
60005 this.activeEditor = ed;
60006 var v = r.data[field];
60007 ed.startEdit(this.view.getCell(row, col), v);
60008 // combo's with 'displayField and name set
60009 if (ed.field.displayField && ed.field.name) {
60010 ed.field.el.dom.value = r.data[ed.field.name];
60014 }).defer(50, this);
60020 * Stops any active editing
60022 stopEditing : function(){
60023 if(this.activeEditor){
60024 this.activeEditor.completeEdit();
60026 this.activeEditor = null;
60030 * Called to get grid's drag proxy text, by default returns this.ddText.
60033 getDragDropText : function(){
60034 var count = this.selModel.getSelectedCell() ? 1 : 0;
60035 return String.format(this.ddText, count, count == 1 ? '' : 's');
60040 * Ext JS Library 1.1.1
60041 * Copyright(c) 2006-2007, Ext JS, LLC.
60043 * Originally Released Under LGPL - original licence link has changed is not relivant.
60046 * <script type="text/javascript">
60049 // private - not really -- you end up using it !
60050 // This is a support class used internally by the Grid components
60053 * @class Roo.grid.GridEditor
60054 * @extends Roo.Editor
60055 * Class for creating and editable grid elements.
60056 * @param {Object} config any settings (must include field)
60058 Roo.grid.GridEditor = function(field, config){
60059 if (!config && field.field) {
60061 field = Roo.factory(config.field, Roo.form);
60063 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
60064 field.monitorTab = false;
60067 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
60070 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
60073 alignment: "tl-tl",
60076 cls: "x-small-editor x-grid-editor",
60081 * Ext JS Library 1.1.1
60082 * Copyright(c) 2006-2007, Ext JS, LLC.
60084 * Originally Released Under LGPL - original licence link has changed is not relivant.
60087 * <script type="text/javascript">
60092 Roo.grid.PropertyRecord = Roo.data.Record.create([
60093 {name:'name',type:'string'}, 'value'
60097 Roo.grid.PropertyStore = function(grid, source){
60099 this.store = new Roo.data.Store({
60100 recordType : Roo.grid.PropertyRecord
60102 this.store.on('update', this.onUpdate, this);
60104 this.setSource(source);
60106 Roo.grid.PropertyStore.superclass.constructor.call(this);
60111 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
60112 setSource : function(o){
60114 this.store.removeAll();
60117 if(this.isEditableValue(o[k])){
60118 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
60121 this.store.loadRecords({records: data}, {}, true);
60124 onUpdate : function(ds, record, type){
60125 if(type == Roo.data.Record.EDIT){
60126 var v = record.data['value'];
60127 var oldValue = record.modified['value'];
60128 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
60129 this.source[record.id] = v;
60131 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
60138 getProperty : function(row){
60139 return this.store.getAt(row);
60142 isEditableValue: function(val){
60143 if(val && val instanceof Date){
60145 }else if(typeof val == 'object' || typeof val == 'function'){
60151 setValue : function(prop, value){
60152 this.source[prop] = value;
60153 this.store.getById(prop).set('value', value);
60156 getSource : function(){
60157 return this.source;
60161 Roo.grid.PropertyColumnModel = function(grid, store){
60164 g.PropertyColumnModel.superclass.constructor.call(this, [
60165 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
60166 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
60168 this.store = store;
60169 this.bselect = Roo.DomHelper.append(document.body, {
60170 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
60171 {tag: 'option', value: 'true', html: 'true'},
60172 {tag: 'option', value: 'false', html: 'false'}
60175 Roo.id(this.bselect);
60178 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
60179 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
60180 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
60181 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
60182 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
60184 this.renderCellDelegate = this.renderCell.createDelegate(this);
60185 this.renderPropDelegate = this.renderProp.createDelegate(this);
60188 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
60192 valueText : 'Value',
60194 dateFormat : 'm/j/Y',
60197 renderDate : function(dateVal){
60198 return dateVal.dateFormat(this.dateFormat);
60201 renderBool : function(bVal){
60202 return bVal ? 'true' : 'false';
60205 isCellEditable : function(colIndex, rowIndex){
60206 return colIndex == 1;
60209 getRenderer : function(col){
60211 this.renderCellDelegate : this.renderPropDelegate;
60214 renderProp : function(v){
60215 return this.getPropertyName(v);
60218 renderCell : function(val){
60220 if(val instanceof Date){
60221 rv = this.renderDate(val);
60222 }else if(typeof val == 'boolean'){
60223 rv = this.renderBool(val);
60225 return Roo.util.Format.htmlEncode(rv);
60228 getPropertyName : function(name){
60229 var pn = this.grid.propertyNames;
60230 return pn && pn[name] ? pn[name] : name;
60233 getCellEditor : function(colIndex, rowIndex){
60234 var p = this.store.getProperty(rowIndex);
60235 var n = p.data['name'], val = p.data['value'];
60237 if(typeof(this.grid.customEditors[n]) == 'string'){
60238 return this.editors[this.grid.customEditors[n]];
60240 if(typeof(this.grid.customEditors[n]) != 'undefined'){
60241 return this.grid.customEditors[n];
60243 if(val instanceof Date){
60244 return this.editors['date'];
60245 }else if(typeof val == 'number'){
60246 return this.editors['number'];
60247 }else if(typeof val == 'boolean'){
60248 return this.editors['boolean'];
60250 return this.editors['string'];
60256 * @class Roo.grid.PropertyGrid
60257 * @extends Roo.grid.EditorGrid
60258 * This class represents the interface of a component based property grid control.
60259 * <br><br>Usage:<pre><code>
60260 var grid = new Roo.grid.PropertyGrid("my-container-id", {
60268 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60269 * The container MUST have some type of size defined for the grid to fill. The container will be
60270 * automatically set to position relative if it isn't already.
60271 * @param {Object} config A config object that sets properties on this grid.
60273 Roo.grid.PropertyGrid = function(container, config){
60274 config = config || {};
60275 var store = new Roo.grid.PropertyStore(this);
60276 this.store = store;
60277 var cm = new Roo.grid.PropertyColumnModel(this, store);
60278 store.store.sort('name', 'ASC');
60279 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
60282 enableColLock:false,
60283 enableColumnMove:false,
60285 trackMouseOver: false,
60288 this.getGridEl().addClass('x-props-grid');
60289 this.lastEditRow = null;
60290 this.on('columnresize', this.onColumnResize, this);
60293 * @event beforepropertychange
60294 * Fires before a property changes (return false to stop?)
60295 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60296 * @param {String} id Record Id
60297 * @param {String} newval New Value
60298 * @param {String} oldval Old Value
60300 "beforepropertychange": true,
60302 * @event propertychange
60303 * Fires after a property changes
60304 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60305 * @param {String} id Record Id
60306 * @param {String} newval New Value
60307 * @param {String} oldval Old Value
60309 "propertychange": true
60311 this.customEditors = this.customEditors || {};
60313 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
60316 * @cfg {Object} customEditors map of colnames=> custom editors.
60317 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
60318 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
60319 * false disables editing of the field.
60323 * @cfg {Object} propertyNames map of property Names to their displayed value
60326 render : function(){
60327 Roo.grid.PropertyGrid.superclass.render.call(this);
60328 this.autoSize.defer(100, this);
60331 autoSize : function(){
60332 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
60334 this.view.fitColumns();
60338 onColumnResize : function(){
60339 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
60343 * Sets the data for the Grid
60344 * accepts a Key => Value object of all the elements avaiable.
60345 * @param {Object} data to appear in grid.
60347 setSource : function(source){
60348 this.store.setSource(source);
60352 * Gets all the data from the grid.
60353 * @return {Object} data data stored in grid
60355 getSource : function(){
60356 return this.store.getSource();
60365 * @class Roo.grid.Calendar
60366 * @extends Roo.grid.Grid
60367 * This class extends the Grid to provide a calendar widget
60368 * <br><br>Usage:<pre><code>
60369 var grid = new Roo.grid.Calendar("my-container-id", {
60372 selModel: mySelectionModel,
60373 autoSizeColumns: true,
60374 monitorWindowResize: false,
60375 trackMouseOver: true
60376 eventstore : real data store..
60382 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60383 * The container MUST have some type of size defined for the grid to fill. The container will be
60384 * automatically set to position relative if it isn't already.
60385 * @param {Object} config A config object that sets properties on this grid.
60387 Roo.grid.Calendar = function(container, config){
60388 // initialize the container
60389 this.container = Roo.get(container);
60390 this.container.update("");
60391 this.container.setStyle("overflow", "hidden");
60392 this.container.addClass('x-grid-container');
60394 this.id = this.container.id;
60396 Roo.apply(this, config);
60397 // check and correct shorthanded configs
60401 for (var r = 0;r < 6;r++) {
60404 for (var c =0;c < 7;c++) {
60408 if (this.eventStore) {
60409 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60410 this.eventStore.on('load',this.onLoad, this);
60411 this.eventStore.on('beforeload',this.clearEvents, this);
60415 this.dataSource = new Roo.data.Store({
60416 proxy: new Roo.data.MemoryProxy(rows),
60417 reader: new Roo.data.ArrayReader({}, [
60418 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60421 this.dataSource.load();
60422 this.ds = this.dataSource;
60423 this.ds.xmodule = this.xmodule || false;
60426 var cellRender = function(v,x,r)
60428 return String.format(
60429 '<div class="fc-day fc-widget-content"><div>' +
60430 '<div class="fc-event-container"></div>' +
60431 '<div class="fc-day-number">{0}</div>'+
60433 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60434 '</div></div>', v);
60439 this.colModel = new Roo.grid.ColumnModel( [
60441 xtype: 'ColumnModel',
60443 dataIndex : 'weekday0',
60445 renderer : cellRender
60448 xtype: 'ColumnModel',
60450 dataIndex : 'weekday1',
60452 renderer : cellRender
60455 xtype: 'ColumnModel',
60457 dataIndex : 'weekday2',
60458 header : 'Tuesday',
60459 renderer : cellRender
60462 xtype: 'ColumnModel',
60464 dataIndex : 'weekday3',
60465 header : 'Wednesday',
60466 renderer : cellRender
60469 xtype: 'ColumnModel',
60471 dataIndex : 'weekday4',
60472 header : 'Thursday',
60473 renderer : cellRender
60476 xtype: 'ColumnModel',
60478 dataIndex : 'weekday5',
60480 renderer : cellRender
60483 xtype: 'ColumnModel',
60485 dataIndex : 'weekday6',
60486 header : 'Saturday',
60487 renderer : cellRender
60490 this.cm = this.colModel;
60491 this.cm.xmodule = this.xmodule || false;
60495 //this.selModel = new Roo.grid.CellSelectionModel();
60496 //this.sm = this.selModel;
60497 //this.selModel.init(this);
60501 this.container.setWidth(this.width);
60505 this.container.setHeight(this.height);
60512 * The raw click event for the entire grid.
60513 * @param {Roo.EventObject} e
60518 * The raw dblclick event for the entire grid.
60519 * @param {Roo.EventObject} e
60523 * @event contextmenu
60524 * The raw contextmenu event for the entire grid.
60525 * @param {Roo.EventObject} e
60527 "contextmenu" : true,
60530 * The raw mousedown event for the entire grid.
60531 * @param {Roo.EventObject} e
60533 "mousedown" : true,
60536 * The raw mouseup event for the entire grid.
60537 * @param {Roo.EventObject} e
60542 * The raw mouseover event for the entire grid.
60543 * @param {Roo.EventObject} e
60545 "mouseover" : true,
60548 * The raw mouseout event for the entire grid.
60549 * @param {Roo.EventObject} e
60554 * The raw keypress event for the entire grid.
60555 * @param {Roo.EventObject} e
60560 * The raw keydown event for the entire grid.
60561 * @param {Roo.EventObject} e
60569 * Fires when a cell is clicked
60570 * @param {Grid} this
60571 * @param {Number} rowIndex
60572 * @param {Number} columnIndex
60573 * @param {Roo.EventObject} e
60575 "cellclick" : true,
60577 * @event celldblclick
60578 * Fires when a cell is double clicked
60579 * @param {Grid} this
60580 * @param {Number} rowIndex
60581 * @param {Number} columnIndex
60582 * @param {Roo.EventObject} e
60584 "celldblclick" : true,
60587 * Fires when a row is clicked
60588 * @param {Grid} this
60589 * @param {Number} rowIndex
60590 * @param {Roo.EventObject} e
60594 * @event rowdblclick
60595 * Fires when a row is double clicked
60596 * @param {Grid} this
60597 * @param {Number} rowIndex
60598 * @param {Roo.EventObject} e
60600 "rowdblclick" : true,
60602 * @event headerclick
60603 * Fires when a header is clicked
60604 * @param {Grid} this
60605 * @param {Number} columnIndex
60606 * @param {Roo.EventObject} e
60608 "headerclick" : true,
60610 * @event headerdblclick
60611 * Fires when a header cell is double clicked
60612 * @param {Grid} this
60613 * @param {Number} columnIndex
60614 * @param {Roo.EventObject} e
60616 "headerdblclick" : true,
60618 * @event rowcontextmenu
60619 * Fires when a row is right clicked
60620 * @param {Grid} this
60621 * @param {Number} rowIndex
60622 * @param {Roo.EventObject} e
60624 "rowcontextmenu" : true,
60626 * @event cellcontextmenu
60627 * Fires when a cell is right clicked
60628 * @param {Grid} this
60629 * @param {Number} rowIndex
60630 * @param {Number} cellIndex
60631 * @param {Roo.EventObject} e
60633 "cellcontextmenu" : true,
60635 * @event headercontextmenu
60636 * Fires when a header is right clicked
60637 * @param {Grid} this
60638 * @param {Number} columnIndex
60639 * @param {Roo.EventObject} e
60641 "headercontextmenu" : true,
60643 * @event bodyscroll
60644 * Fires when the body element is scrolled
60645 * @param {Number} scrollLeft
60646 * @param {Number} scrollTop
60648 "bodyscroll" : true,
60650 * @event columnresize
60651 * Fires when the user resizes a column
60652 * @param {Number} columnIndex
60653 * @param {Number} newSize
60655 "columnresize" : true,
60657 * @event columnmove
60658 * Fires when the user moves a column
60659 * @param {Number} oldIndex
60660 * @param {Number} newIndex
60662 "columnmove" : true,
60665 * Fires when row(s) start being dragged
60666 * @param {Grid} this
60667 * @param {Roo.GridDD} dd The drag drop object
60668 * @param {event} e The raw browser event
60670 "startdrag" : true,
60673 * Fires when a drag operation is complete
60674 * @param {Grid} this
60675 * @param {Roo.GridDD} dd The drag drop object
60676 * @param {event} e The raw browser event
60681 * Fires when dragged row(s) are dropped on a valid DD target
60682 * @param {Grid} this
60683 * @param {Roo.GridDD} dd The drag drop object
60684 * @param {String} targetId The target drag drop object
60685 * @param {event} e The raw browser event
60690 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60691 * @param {Grid} this
60692 * @param {Roo.GridDD} dd The drag drop object
60693 * @param {String} targetId The target drag drop object
60694 * @param {event} e The raw browser event
60699 * Fires when the dragged row(s) first cross another DD target while being dragged
60700 * @param {Grid} this
60701 * @param {Roo.GridDD} dd The drag drop object
60702 * @param {String} targetId The target drag drop object
60703 * @param {event} e The raw browser event
60705 "dragenter" : true,
60708 * Fires when the dragged row(s) leave another DD target while being dragged
60709 * @param {Grid} this
60710 * @param {Roo.GridDD} dd The drag drop object
60711 * @param {String} targetId The target drag drop object
60712 * @param {event} e The raw browser event
60717 * Fires when a row is rendered, so you can change add a style to it.
60718 * @param {GridView} gridview The grid view
60719 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60725 * Fires when the grid is rendered
60726 * @param {Grid} grid
60731 * Fires when a date is selected
60732 * @param {DatePicker} this
60733 * @param {Date} date The selected date
60737 * @event monthchange
60738 * Fires when the displayed month changes
60739 * @param {DatePicker} this
60740 * @param {Date} date The selected month
60742 'monthchange': true,
60744 * @event evententer
60745 * Fires when mouse over an event
60746 * @param {Calendar} this
60747 * @param {event} Event
60749 'evententer': true,
60751 * @event eventleave
60752 * Fires when the mouse leaves an
60753 * @param {Calendar} this
60756 'eventleave': true,
60758 * @event eventclick
60759 * Fires when the mouse click an
60760 * @param {Calendar} this
60763 'eventclick': true,
60765 * @event eventrender
60766 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60767 * @param {Calendar} this
60768 * @param {data} data to be modified
60770 'eventrender': true
60774 Roo.grid.Grid.superclass.constructor.call(this);
60775 this.on('render', function() {
60776 this.view.el.addClass('x-grid-cal');
60778 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60782 if (!Roo.grid.Calendar.style) {
60783 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60786 '.x-grid-cal .x-grid-col' : {
60787 height: 'auto !important',
60788 'vertical-align': 'top'
60790 '.x-grid-cal .fc-event-hori' : {
60801 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60803 * @cfg {Store} eventStore The store that loads events.
60808 activeDate : false,
60811 monitorWindowResize : false,
60814 resizeColumns : function() {
60815 var col = (this.view.el.getWidth() / 7) - 3;
60816 // loop through cols, and setWidth
60817 for(var i =0 ; i < 7 ; i++){
60818 this.cm.setColumnWidth(i, col);
60821 setDate :function(date) {
60823 Roo.log('setDate?');
60825 this.resizeColumns();
60826 var vd = this.activeDate;
60827 this.activeDate = date;
60828 // if(vd && this.el){
60829 // var t = date.getTime();
60830 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60831 // Roo.log('using add remove');
60833 // this.fireEvent('monthchange', this, date);
60835 // this.cells.removeClass("fc-state-highlight");
60836 // this.cells.each(function(c){
60837 // if(c.dateValue == t){
60838 // c.addClass("fc-state-highlight");
60839 // setTimeout(function(){
60840 // try{c.dom.firstChild.focus();}catch(e){}
60850 var days = date.getDaysInMonth();
60852 var firstOfMonth = date.getFirstDateOfMonth();
60853 var startingPos = firstOfMonth.getDay()-this.startDay;
60855 if(startingPos < this.startDay){
60859 var pm = date.add(Date.MONTH, -1);
60860 var prevStart = pm.getDaysInMonth()-startingPos;
60864 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60866 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60867 //this.cells.addClassOnOver('fc-state-hover');
60869 var cells = this.cells.elements;
60870 var textEls = this.textNodes;
60872 //Roo.each(cells, function(cell){
60873 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60876 days += startingPos;
60878 // convert everything to numbers so it's fast
60879 var day = 86400000;
60880 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60883 //Roo.log(prevStart);
60885 var today = new Date().clearTime().getTime();
60886 var sel = date.clearTime().getTime();
60887 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60888 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60889 var ddMatch = this.disabledDatesRE;
60890 var ddText = this.disabledDatesText;
60891 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60892 var ddaysText = this.disabledDaysText;
60893 var format = this.format;
60895 var setCellClass = function(cal, cell){
60897 //Roo.log('set Cell Class');
60899 var t = d.getTime();
60904 cell.dateValue = t;
60906 cell.className += " fc-today";
60907 cell.className += " fc-state-highlight";
60908 cell.title = cal.todayText;
60911 // disable highlight in other month..
60912 cell.className += " fc-state-highlight";
60917 //cell.className = " fc-state-disabled";
60918 cell.title = cal.minText;
60922 //cell.className = " fc-state-disabled";
60923 cell.title = cal.maxText;
60927 if(ddays.indexOf(d.getDay()) != -1){
60928 // cell.title = ddaysText;
60929 // cell.className = " fc-state-disabled";
60932 if(ddMatch && format){
60933 var fvalue = d.dateFormat(format);
60934 if(ddMatch.test(fvalue)){
60935 cell.title = ddText.replace("%0", fvalue);
60936 cell.className = " fc-state-disabled";
60940 if (!cell.initialClassName) {
60941 cell.initialClassName = cell.dom.className;
60944 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60949 for(; i < startingPos; i++) {
60950 cells[i].dayName = (++prevStart);
60951 Roo.log(textEls[i]);
60952 d.setDate(d.getDate()+1);
60954 //cells[i].className = "fc-past fc-other-month";
60955 setCellClass(this, cells[i]);
60960 for(; i < days; i++){
60961 intDay = i - startingPos + 1;
60962 cells[i].dayName = (intDay);
60963 d.setDate(d.getDate()+1);
60965 cells[i].className = ''; // "x-date-active";
60966 setCellClass(this, cells[i]);
60970 for(; i < 42; i++) {
60971 //textEls[i].innerHTML = (++extraDays);
60973 d.setDate(d.getDate()+1);
60974 cells[i].dayName = (++extraDays);
60975 cells[i].className = "fc-future fc-other-month";
60976 setCellClass(this, cells[i]);
60979 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60981 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60983 // this will cause all the cells to mis
60986 for (var r = 0;r < 6;r++) {
60987 for (var c =0;c < 7;c++) {
60988 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60992 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60993 for(i=0;i<cells.length;i++) {
60995 this.cells.elements[i].dayName = cells[i].dayName ;
60996 this.cells.elements[i].className = cells[i].className;
60997 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
60998 this.cells.elements[i].title = cells[i].title ;
60999 this.cells.elements[i].dateValue = cells[i].dateValue ;
61005 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
61006 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
61008 ////if(totalRows != 6){
61009 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
61010 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
61013 this.fireEvent('monthchange', this, date);
61018 * Returns the grid's SelectionModel.
61019 * @return {SelectionModel}
61021 getSelectionModel : function(){
61022 if(!this.selModel){
61023 this.selModel = new Roo.grid.CellSelectionModel();
61025 return this.selModel;
61029 this.eventStore.load()
61035 findCell : function(dt) {
61036 dt = dt.clearTime().getTime();
61038 this.cells.each(function(c){
61039 //Roo.log("check " +c.dateValue + '?=' + dt);
61040 if(c.dateValue == dt){
61050 findCells : function(rec) {
61051 var s = rec.data.start_dt.clone().clearTime().getTime();
61053 var e= rec.data.end_dt.clone().clearTime().getTime();
61056 this.cells.each(function(c){
61057 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
61059 if(c.dateValue > e){
61062 if(c.dateValue < s){
61071 findBestRow: function(cells)
61075 for (var i =0 ; i < cells.length;i++) {
61076 ret = Math.max(cells[i].rows || 0,ret);
61083 addItem : function(rec)
61085 // look for vertical location slot in
61086 var cells = this.findCells(rec);
61088 rec.row = this.findBestRow(cells);
61090 // work out the location.
61094 for(var i =0; i < cells.length; i++) {
61102 if (crow.start.getY() == cells[i].getY()) {
61104 crow.end = cells[i];
61120 for (var i = 0; i < cells.length;i++) {
61121 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
61128 clearEvents: function() {
61130 if (!this.eventStore.getCount()) {
61133 // reset number of rows in cells.
61134 Roo.each(this.cells.elements, function(c){
61138 this.eventStore.each(function(e) {
61139 this.clearEvent(e);
61144 clearEvent : function(ev)
61147 Roo.each(ev.els, function(el) {
61148 el.un('mouseenter' ,this.onEventEnter, this);
61149 el.un('mouseleave' ,this.onEventLeave, this);
61157 renderEvent : function(ev,ctr) {
61159 ctr = this.view.el.select('.fc-event-container',true).first();
61163 this.clearEvent(ev);
61169 var cells = ev.cells;
61170 var rows = ev.rows;
61171 this.fireEvent('eventrender', this, ev);
61173 for(var i =0; i < rows.length; i++) {
61177 cls += ' fc-event-start';
61179 if ((i+1) == rows.length) {
61180 cls += ' fc-event-end';
61183 //Roo.log(ev.data);
61184 // how many rows should it span..
61185 var cg = this.eventTmpl.append(ctr,Roo.apply({
61188 }, ev.data) , true);
61191 cg.on('mouseenter' ,this.onEventEnter, this, ev);
61192 cg.on('mouseleave' ,this.onEventLeave, this, ev);
61193 cg.on('click', this.onEventClick, this, ev);
61197 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
61198 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
61201 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
61202 cg.setWidth(ebox.right - sbox.x -2);
61206 renderEvents: function()
61208 // first make sure there is enough space..
61210 if (!this.eventTmpl) {
61211 this.eventTmpl = new Roo.Template(
61212 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
61213 '<div class="fc-event-inner">' +
61214 '<span class="fc-event-time">{time}</span>' +
61215 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
61217 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
61225 this.cells.each(function(c) {
61226 //Roo.log(c.select('.fc-day-content div',true).first());
61227 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
61230 var ctr = this.view.el.select('.fc-event-container',true).first();
61233 this.eventStore.each(function(ev){
61235 this.renderEvent(ev);
61239 this.view.layout();
61243 onEventEnter: function (e, el,event,d) {
61244 this.fireEvent('evententer', this, el, event);
61247 onEventLeave: function (e, el,event,d) {
61248 this.fireEvent('eventleave', this, el, event);
61251 onEventClick: function (e, el,event,d) {
61252 this.fireEvent('eventclick', this, el, event);
61255 onMonthChange: function () {
61259 onLoad: function () {
61261 //Roo.log('calendar onload');
61263 if(this.eventStore.getCount() > 0){
61267 this.eventStore.each(function(d){
61272 if (typeof(add.end_dt) == 'undefined') {
61273 Roo.log("Missing End time in calendar data: ");
61277 if (typeof(add.start_dt) == 'undefined') {
61278 Roo.log("Missing Start time in calendar data: ");
61282 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
61283 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
61284 add.id = add.id || d.id;
61285 add.title = add.title || '??';
61293 this.renderEvents();
61303 render : function ()
61307 if (!this.view.el.hasClass('course-timesheet')) {
61308 this.view.el.addClass('course-timesheet');
61310 if (this.tsStyle) {
61315 Roo.log(_this.grid.view.el.getWidth());
61318 this.tsStyle = Roo.util.CSS.createStyleSheet({
61319 '.course-timesheet .x-grid-row' : {
61322 '.x-grid-row td' : {
61323 'vertical-align' : 0
61325 '.course-edit-link' : {
61327 'text-overflow' : 'ellipsis',
61328 'overflow' : 'hidden',
61329 'white-space' : 'nowrap',
61330 'cursor' : 'pointer'
61335 '.de-act-sup-link' : {
61336 'color' : 'purple',
61337 'text-decoration' : 'line-through'
61341 'text-decoration' : 'line-through'
61343 '.course-timesheet .course-highlight' : {
61344 'border-top-style': 'dashed !important',
61345 'border-bottom-bottom': 'dashed !important'
61347 '.course-timesheet .course-item' : {
61348 'font-family' : 'tahoma, arial, helvetica',
61349 'font-size' : '11px',
61350 'overflow' : 'hidden',
61351 'padding-left' : '10px',
61352 'padding-right' : '10px',
61353 'padding-top' : '10px'
61361 monitorWindowResize : false,
61362 cellrenderer : function(v,x,r)
61367 xtype: 'CellSelectionModel',
61374 beforeload : function (_self, options)
61376 options.params = options.params || {};
61377 options.params._month = _this.monthField.getValue();
61378 options.params.limit = 9999;
61379 options.params['sort'] = 'when_dt';
61380 options.params['dir'] = 'ASC';
61381 this.proxy.loadResponse = this.loadResponse;
61383 //this.addColumns();
61385 load : function (_self, records, options)
61387 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
61388 // if you click on the translation.. you can edit it...
61389 var el = Roo.get(this);
61390 var id = el.dom.getAttribute('data-id');
61391 var d = el.dom.getAttribute('data-date');
61392 var t = el.dom.getAttribute('data-time');
61393 //var id = this.child('span').dom.textContent;
61396 Pman.Dialog.CourseCalendar.show({
61400 productitem_active : id ? 1 : 0
61402 _this.grid.ds.load({});
61407 _this.panel.fireEvent('resize', [ '', '' ]);
61410 loadResponse : function(o, success, response){
61411 // this is overridden on before load..
61413 Roo.log("our code?");
61414 //Roo.log(success);
61415 //Roo.log(response)
61416 delete this.activeRequest;
61418 this.fireEvent("loadexception", this, o, response);
61419 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61424 result = o.reader.read(response);
61426 Roo.log("load exception?");
61427 this.fireEvent("loadexception", this, o, response, e);
61428 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61431 Roo.log("ready...");
61432 // loop through result.records;
61433 // and set this.tdate[date] = [] << array of records..
61435 Roo.each(result.records, function(r){
61437 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61438 _this.tdata[r.data.when_dt.format('j')] = [];
61440 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61443 //Roo.log(_this.tdata);
61445 result.records = [];
61446 result.totalRecords = 6;
61448 // let's generate some duumy records for the rows.
61449 //var st = _this.dateField.getValue();
61451 // work out monday..
61452 //st = st.add(Date.DAY, -1 * st.format('w'));
61454 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61456 var firstOfMonth = date.getFirstDayOfMonth();
61457 var days = date.getDaysInMonth();
61459 var firstAdded = false;
61460 for (var i = 0; i < result.totalRecords ; i++) {
61461 //var d= st.add(Date.DAY, i);
61464 for(var w = 0 ; w < 7 ; w++){
61465 if(!firstAdded && firstOfMonth != w){
61472 var dd = (d > 0 && d < 10) ? "0"+d : d;
61473 row['weekday'+w] = String.format(
61474 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61475 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61477 date.format('Y-m-')+dd
61480 if(typeof(_this.tdata[d]) != 'undefined'){
61481 Roo.each(_this.tdata[d], function(r){
61485 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61486 if(r.parent_id*1>0){
61487 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61490 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61491 deactive = 'de-act-link';
61494 row['weekday'+w] += String.format(
61495 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61497 r.product_id_name, //1
61498 r.when_dt.format('h:ia'), //2
61508 // only do this if something added..
61510 result.records.push(_this.grid.dataSource.reader.newRow(row));
61514 // push it twice. (second one with an hour..
61518 this.fireEvent("load", this, o, o.request.arg);
61519 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61521 sortInfo : {field: 'when_dt', direction : 'ASC' },
61523 xtype: 'HttpProxy',
61526 url : baseURL + '/Roo/Shop_course.php'
61529 xtype: 'JsonReader',
61546 'name': 'parent_id',
61550 'name': 'product_id',
61554 'name': 'productitem_id',
61572 click : function (_self, e)
61574 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61575 sd.setMonth(sd.getMonth()-1);
61576 _this.monthField.setValue(sd.format('Y-m-d'));
61577 _this.grid.ds.load({});
61583 xtype: 'Separator',
61587 xtype: 'MonthField',
61590 render : function (_self)
61592 _this.monthField = _self;
61593 // _this.monthField.set today
61595 select : function (combo, date)
61597 _this.grid.ds.load({});
61600 value : (function() { return new Date(); })()
61603 xtype: 'Separator',
61609 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61619 click : function (_self, e)
61621 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61622 sd.setMonth(sd.getMonth()+1);
61623 _this.monthField.setValue(sd.format('Y-m-d'));
61624 _this.grid.ds.load({});
61637 * Ext JS Library 1.1.1
61638 * Copyright(c) 2006-2007, Ext JS, LLC.
61640 * Originally Released Under LGPL - original licence link has changed is not relivant.
61643 * <script type="text/javascript">
61647 * @class Roo.LoadMask
61648 * A simple utility class for generically masking elements while loading data. If the element being masked has
61649 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61650 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61651 * element's UpdateManager load indicator and will be destroyed after the initial load.
61653 * Create a new LoadMask
61654 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61655 * @param {Object} config The config object
61657 Roo.LoadMask = function(el, config){
61658 this.el = Roo.get(el);
61659 Roo.apply(this, config);
61661 this.store.on('beforeload', this.onBeforeLoad, this);
61662 this.store.on('load', this.onLoad, this);
61663 this.store.on('loadexception', this.onLoadException, this);
61664 this.removeMask = false;
61666 var um = this.el.getUpdateManager();
61667 um.showLoadIndicator = false; // disable the default indicator
61668 um.on('beforeupdate', this.onBeforeLoad, this);
61669 um.on('update', this.onLoad, this);
61670 um.on('failure', this.onLoad, this);
61671 this.removeMask = true;
61675 Roo.LoadMask.prototype = {
61677 * @cfg {Boolean} removeMask
61678 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61679 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61681 removeMask : false,
61683 * @cfg {String} msg
61684 * The text to display in a centered loading message box (defaults to 'Loading...')
61686 msg : 'Loading...',
61688 * @cfg {String} msgCls
61689 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61691 msgCls : 'x-mask-loading',
61694 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61700 * Disables the mask to prevent it from being displayed
61702 disable : function(){
61703 this.disabled = true;
61707 * Enables the mask so that it can be displayed
61709 enable : function(){
61710 this.disabled = false;
61713 onLoadException : function()
61715 Roo.log(arguments);
61717 if (typeof(arguments[3]) != 'undefined') {
61718 Roo.MessageBox.alert("Error loading",arguments[3]);
61722 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61723 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61730 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61733 onLoad : function()
61735 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61739 onBeforeLoad : function(){
61740 if(!this.disabled){
61741 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61746 destroy : function(){
61748 this.store.un('beforeload', this.onBeforeLoad, this);
61749 this.store.un('load', this.onLoad, this);
61750 this.store.un('loadexception', this.onLoadException, this);
61752 var um = this.el.getUpdateManager();
61753 um.un('beforeupdate', this.onBeforeLoad, this);
61754 um.un('update', this.onLoad, this);
61755 um.un('failure', this.onLoad, this);
61760 * Ext JS Library 1.1.1
61761 * Copyright(c) 2006-2007, Ext JS, LLC.
61763 * Originally Released Under LGPL - original licence link has changed is not relivant.
61766 * <script type="text/javascript">
61771 * @class Roo.XTemplate
61772 * @extends Roo.Template
61773 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61775 var t = new Roo.XTemplate(
61776 '<select name="{name}">',
61777 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61781 // then append, applying the master template values
61784 * Supported features:
61789 {a_variable} - output encoded.
61790 {a_variable.format:("Y-m-d")} - call a method on the variable
61791 {a_variable:raw} - unencoded output
61792 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61793 {a_variable:this.method_on_template(...)} - call a method on the template object.
61798 <tpl for="a_variable or condition.."></tpl>
61799 <tpl if="a_variable or condition"></tpl>
61800 <tpl exec="some javascript"></tpl>
61801 <tpl name="named_template"></tpl> (experimental)
61803 <tpl for="."></tpl> - just iterate the property..
61804 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61808 Roo.XTemplate = function()
61810 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61817 Roo.extend(Roo.XTemplate, Roo.Template, {
61820 * The various sub templates
61825 * basic tag replacing syntax
61828 * // you can fake an object call by doing this
61832 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61835 * compile the template
61837 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61840 compile: function()
61844 s = ['<tpl>', s, '</tpl>'].join('');
61846 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61847 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61848 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61849 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61850 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61855 while(true == !!(m = s.match(re))){
61856 var forMatch = m[0].match(nameRe),
61857 ifMatch = m[0].match(ifRe),
61858 execMatch = m[0].match(execRe),
61859 namedMatch = m[0].match(namedRe),
61864 name = forMatch && forMatch[1] ? forMatch[1] : '';
61867 // if - puts fn into test..
61868 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61870 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61875 // exec - calls a function... returns empty if true is returned.
61876 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61878 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61886 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61887 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61888 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61891 var uid = namedMatch ? namedMatch[1] : id;
61895 id: namedMatch ? namedMatch[1] : id,
61902 s = s.replace(m[0], '');
61904 s = s.replace(m[0], '{xtpl'+ id + '}');
61909 for(var i = tpls.length-1; i >= 0; --i){
61910 this.compileTpl(tpls[i]);
61911 this.tpls[tpls[i].id] = tpls[i];
61913 this.master = tpls[tpls.length-1];
61917 * same as applyTemplate, except it's done to one of the subTemplates
61918 * when using named templates, you can do:
61920 * var str = pl.applySubTemplate('your-name', values);
61923 * @param {Number} id of the template
61924 * @param {Object} values to apply to template
61925 * @param {Object} parent (normaly the instance of this object)
61927 applySubTemplate : function(id, values, parent)
61931 var t = this.tpls[id];
61935 if(t.test && !t.test.call(this, values, parent)){
61939 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61940 Roo.log(e.toString());
61946 if(t.exec && t.exec.call(this, values, parent)){
61950 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61951 Roo.log(e.toString());
61956 var vs = t.target ? t.target.call(this, values, parent) : values;
61957 parent = t.target ? values : parent;
61958 if(t.target && vs instanceof Array){
61960 for(var i = 0, len = vs.length; i < len; i++){
61961 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61963 return buf.join('');
61965 return t.compiled.call(this, vs, parent);
61967 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61968 Roo.log(e.toString());
61969 Roo.log(t.compiled);
61974 compileTpl : function(tpl)
61976 var fm = Roo.util.Format;
61977 var useF = this.disableFormats !== true;
61978 var sep = Roo.isGecko ? "+" : ",";
61979 var undef = function(str) {
61980 Roo.log("Property not found :" + str);
61984 var fn = function(m, name, format, args)
61986 //Roo.log(arguments);
61987 args = args ? args.replace(/\\'/g,"'") : args;
61988 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61989 if (typeof(format) == 'undefined') {
61990 format= 'htmlEncode';
61992 if (format == 'raw' ) {
61996 if(name.substr(0, 4) == 'xtpl'){
61997 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
62000 // build an array of options to determine if value is undefined..
62002 // basically get 'xxxx.yyyy' then do
62003 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
62004 // (function () { Roo.log("Property not found"); return ''; })() :
62009 Roo.each(name.split('.'), function(st) {
62010 lookfor += (lookfor.length ? '.': '') + st;
62011 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
62014 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
62017 if(format && useF){
62019 args = args ? ',' + args : "";
62021 if(format.substr(0, 5) != "this."){
62022 format = "fm." + format + '(';
62024 format = 'this.call("'+ format.substr(5) + '", ';
62028 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
62032 // called with xxyx.yuu:(test,test)
62034 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
62036 // raw.. - :raw modifier..
62037 return "'"+ sep + udef_st + name + ")"+sep+"'";
62041 // branched to use + in gecko and [].join() in others
62043 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
62044 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
62047 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
62048 body.push(tpl.body.replace(/(\r\n|\n)/g,
62049 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
62050 body.push("'].join('');};};");
62051 body = body.join('');
62054 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
62056 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
62062 applyTemplate : function(values){
62063 return this.master.compiled.call(this, values, {});
62064 //var s = this.subs;
62067 apply : function(){
62068 return this.applyTemplate.apply(this, arguments);
62073 Roo.XTemplate.from = function(el){
62074 el = Roo.getDom(el);
62075 return new Roo.XTemplate(el.value || el.innerHTML);