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){
23882 if(success !== false){
23883 this.fireEvent("load", this, [], options, o);
23885 if(options.callback){
23886 options.callback.call(options.scope || this, [], options, false);
23890 // if data returned failure - throw an exception.
23891 if (o.success === false) {
23892 // show a message if no listener is registered.
23893 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23894 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23896 // loadmask wil be hooked into this..
23897 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23900 var r = o.records, t = o.totalRecords || r.length;
23902 this.fireEvent("beforeloadadd", this, r, options, o);
23904 if(!options || options.add !== true){
23905 if(this.pruneModifiedRecords){
23906 this.modified = [];
23908 for(var i = 0, len = r.length; i < len; i++){
23912 this.data = this.snapshot;
23913 delete this.snapshot;
23916 this.data.addAll(r);
23917 this.totalLength = t;
23919 this.fireEvent("datachanged", this);
23921 this.totalLength = Math.max(t, this.data.length+r.length);
23925 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23927 var e = new Roo.data.Record({});
23929 e.set(this.parent.displayField, this.parent.emptyTitle);
23930 e.set(this.parent.valueField, '');
23935 this.fireEvent("load", this, r, options, o);
23936 if(options.callback){
23937 options.callback.call(options.scope || this, r, options, true);
23943 * Loads data from a passed data block. A Reader which understands the format of the data
23944 * must have been configured in the constructor.
23945 * @param {Object} data The data block from which to read the Records. The format of the data expected
23946 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23947 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23949 loadData : function(o, append){
23950 var r = this.reader.readRecords(o);
23951 this.loadRecords(r, {add: append}, true);
23955 * using 'cn' the nested child reader read the child array into it's child stores.
23956 * @param {Object} rec The record with a 'children array
23958 loadDataFromChildren : function(rec)
23960 this.loadData(this.reader.toLoadData(rec));
23965 * Gets the number of cached records.
23967 * <em>If using paging, this may not be the total size of the dataset. If the data object
23968 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23969 * the data set size</em>
23971 getCount : function(){
23972 return this.data.length || 0;
23976 * Gets the total number of records in the dataset as returned by the server.
23978 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23979 * the dataset size</em>
23981 getTotalCount : function(){
23982 return this.totalLength || 0;
23986 * Returns the sort state of the Store as an object with two properties:
23988 field {String} The name of the field by which the Records are sorted
23989 direction {String} The sort order, "ASC" or "DESC"
23992 getSortState : function(){
23993 return this.sortInfo;
23997 applySort : function(){
23998 if(this.sortInfo && !this.remoteSort){
23999 var s = this.sortInfo, f = s.field;
24000 var st = this.fields.get(f).sortType;
24001 var fn = function(r1, r2){
24002 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
24003 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
24005 this.data.sort(s.direction, fn);
24006 if(this.snapshot && this.snapshot != this.data){
24007 this.snapshot.sort(s.direction, fn);
24013 * Sets the default sort column and order to be used by the next load operation.
24014 * @param {String} fieldName The name of the field to sort by.
24015 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24017 setDefaultSort : function(field, dir){
24018 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
24022 * Sort the Records.
24023 * If remote sorting is used, the sort is performed on the server, and the cache is
24024 * reloaded. If local sorting is used, the cache is sorted internally.
24025 * @param {String} fieldName The name of the field to sort by.
24026 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24028 sort : function(fieldName, dir){
24029 var f = this.fields.get(fieldName);
24031 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
24033 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
24034 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
24039 this.sortToggle[f.name] = dir;
24040 this.sortInfo = {field: f.name, direction: dir};
24041 if(!this.remoteSort){
24043 this.fireEvent("datachanged", this);
24045 this.load(this.lastOptions);
24050 * Calls the specified function for each of the Records in the cache.
24051 * @param {Function} fn The function to call. The Record is passed as the first parameter.
24052 * Returning <em>false</em> aborts and exits the iteration.
24053 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
24055 each : function(fn, scope){
24056 this.data.each(fn, scope);
24060 * Gets all records modified since the last commit. Modified records are persisted across load operations
24061 * (e.g., during paging).
24062 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
24064 getModifiedRecords : function(){
24065 return this.modified;
24069 createFilterFn : function(property, value, anyMatch){
24070 if(!value.exec){ // not a regex
24071 value = String(value);
24072 if(value.length == 0){
24075 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
24077 return function(r){
24078 return value.test(r.data[property]);
24083 * Sums the value of <i>property</i> for each record between start and end and returns the result.
24084 * @param {String} property A field on your records
24085 * @param {Number} start The record index to start at (defaults to 0)
24086 * @param {Number} end The last record index to include (defaults to length - 1)
24087 * @return {Number} The sum
24089 sum : function(property, start, end){
24090 var rs = this.data.items, v = 0;
24091 start = start || 0;
24092 end = (end || end === 0) ? end : rs.length-1;
24094 for(var i = start; i <= end; i++){
24095 v += (rs[i].data[property] || 0);
24101 * Filter the records by a specified property.
24102 * @param {String} field A field on your records
24103 * @param {String/RegExp} value Either a string that the field
24104 * should start with or a RegExp to test against the field
24105 * @param {Boolean} anyMatch True to match any part not just the beginning
24107 filter : function(property, value, anyMatch){
24108 var fn = this.createFilterFn(property, value, anyMatch);
24109 return fn ? this.filterBy(fn) : this.clearFilter();
24113 * Filter by a function. The specified function will be called with each
24114 * record in this data source. If the function returns true the record is included,
24115 * otherwise it is filtered.
24116 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24117 * @param {Object} scope (optional) The scope of the function (defaults to this)
24119 filterBy : function(fn, scope){
24120 this.snapshot = this.snapshot || this.data;
24121 this.data = this.queryBy(fn, scope||this);
24122 this.fireEvent("datachanged", this);
24126 * Query the records by a specified property.
24127 * @param {String} field A field on your records
24128 * @param {String/RegExp} value Either a string that the field
24129 * should start with or a RegExp to test against the field
24130 * @param {Boolean} anyMatch True to match any part not just the beginning
24131 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24133 query : function(property, value, anyMatch){
24134 var fn = this.createFilterFn(property, value, anyMatch);
24135 return fn ? this.queryBy(fn) : this.data.clone();
24139 * Query by a function. The specified function will be called with each
24140 * record in this data source. If the function returns true the record is included
24142 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24143 * @param {Object} scope (optional) The scope of the function (defaults to this)
24144 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24146 queryBy : function(fn, scope){
24147 var data = this.snapshot || this.data;
24148 return data.filterBy(fn, scope||this);
24152 * Collects unique values for a particular dataIndex from this store.
24153 * @param {String} dataIndex The property to collect
24154 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24155 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24156 * @return {Array} An array of the unique values
24158 collect : function(dataIndex, allowNull, bypassFilter){
24159 var d = (bypassFilter === true && this.snapshot) ?
24160 this.snapshot.items : this.data.items;
24161 var v, sv, r = [], l = {};
24162 for(var i = 0, len = d.length; i < len; i++){
24163 v = d[i].data[dataIndex];
24165 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24174 * Revert to a view of the Record cache with no filtering applied.
24175 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24177 clearFilter : function(suppressEvent){
24178 if(this.snapshot && this.snapshot != this.data){
24179 this.data = this.snapshot;
24180 delete this.snapshot;
24181 if(suppressEvent !== true){
24182 this.fireEvent("datachanged", this);
24188 afterEdit : function(record){
24189 if(this.modified.indexOf(record) == -1){
24190 this.modified.push(record);
24192 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24196 afterReject : function(record){
24197 this.modified.remove(record);
24198 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24202 afterCommit : function(record){
24203 this.modified.remove(record);
24204 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24208 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24209 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24211 commitChanges : function(){
24212 var m = this.modified.slice(0);
24213 this.modified = [];
24214 for(var i = 0, len = m.length; i < len; i++){
24220 * Cancel outstanding changes on all changed records.
24222 rejectChanges : function(){
24223 var m = this.modified.slice(0);
24224 this.modified = [];
24225 for(var i = 0, len = m.length; i < len; i++){
24230 onMetaChange : function(meta, rtype, o){
24231 this.recordType = rtype;
24232 this.fields = rtype.prototype.fields;
24233 delete this.snapshot;
24234 this.sortInfo = meta.sortInfo || this.sortInfo;
24235 this.modified = [];
24236 this.fireEvent('metachange', this, this.reader.meta);
24239 moveIndex : function(data, type)
24241 var index = this.indexOf(data);
24243 var newIndex = index + type;
24247 this.insert(newIndex, data);
24252 * Ext JS Library 1.1.1
24253 * Copyright(c) 2006-2007, Ext JS, LLC.
24255 * Originally Released Under LGPL - original licence link has changed is not relivant.
24258 * <script type="text/javascript">
24262 * @class Roo.data.SimpleStore
24263 * @extends Roo.data.Store
24264 * Small helper class to make creating Stores from Array data easier.
24265 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24266 * @cfg {Array} fields An array of field definition objects, or field name strings.
24267 * @cfg {Object} an existing reader (eg. copied from another store)
24268 * @cfg {Array} data The multi-dimensional array of data
24269 * @cfg {Roo.data.DataProxy} proxy [not-required]
24270 * @cfg {Roo.data.Reader} reader [not-required]
24272 * @param {Object} config
24274 Roo.data.SimpleStore = function(config)
24276 Roo.data.SimpleStore.superclass.constructor.call(this, {
24278 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24281 Roo.data.Record.create(config.fields)
24283 proxy : new Roo.data.MemoryProxy(config.data)
24287 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24289 * Ext JS Library 1.1.1
24290 * Copyright(c) 2006-2007, Ext JS, LLC.
24292 * Originally Released Under LGPL - original licence link has changed is not relivant.
24295 * <script type="text/javascript">
24300 * @extends Roo.data.Store
24301 * @class Roo.data.JsonStore
24302 * Small helper class to make creating Stores for JSON data easier. <br/>
24304 var store = new Roo.data.JsonStore({
24305 url: 'get-images.php',
24307 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24310 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24311 * JsonReader and HttpProxy (unless inline data is provided).</b>
24312 * @cfg {Array} fields An array of field definition objects, or field name strings.
24314 * @param {Object} config
24316 Roo.data.JsonStore = function(c){
24317 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24318 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24319 reader: new Roo.data.JsonReader(c, c.fields)
24322 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
24324 * Ext JS Library 1.1.1
24325 * Copyright(c) 2006-2007, Ext JS, LLC.
24327 * Originally Released Under LGPL - original licence link has changed is not relivant.
24330 * <script type="text/javascript">
24334 Roo.data.Field = function(config){
24335 if(typeof config == "string"){
24336 config = {name: config};
24338 Roo.apply(this, config);
24341 this.type = "auto";
24344 var st = Roo.data.SortTypes;
24345 // named sortTypes are supported, here we look them up
24346 if(typeof this.sortType == "string"){
24347 this.sortType = st[this.sortType];
24350 // set default sortType for strings and dates
24351 if(!this.sortType){
24354 this.sortType = st.asUCString;
24357 this.sortType = st.asDate;
24360 this.sortType = st.none;
24365 var stripRe = /[\$,%]/g;
24367 // prebuilt conversion function for this field, instead of
24368 // switching every time we're reading a value
24370 var cv, dateFormat = this.dateFormat;
24375 cv = function(v){ return v; };
24378 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24382 return v !== undefined && v !== null && v !== '' ?
24383 parseInt(String(v).replace(stripRe, ""), 10) : '';
24388 return v !== undefined && v !== null && v !== '' ?
24389 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24394 cv = function(v){ return v === true || v === "true" || v == 1; };
24401 if(v instanceof Date){
24405 if(dateFormat == "timestamp"){
24406 return new Date(v*1000);
24408 return Date.parseDate(v, dateFormat);
24410 var parsed = Date.parse(v);
24411 return parsed ? new Date(parsed) : null;
24420 Roo.data.Field.prototype = {
24428 * Ext JS Library 1.1.1
24429 * Copyright(c) 2006-2007, Ext JS, LLC.
24431 * Originally Released Under LGPL - original licence link has changed is not relivant.
24434 * <script type="text/javascript">
24437 // Base class for reading structured data from a data source. This class is intended to be
24438 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24441 * @class Roo.data.DataReader
24443 * Base class for reading structured data from a data source. This class is intended to be
24444 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24447 Roo.data.DataReader = function(meta, recordType){
24451 this.recordType = recordType instanceof Array ?
24452 Roo.data.Record.create(recordType) : recordType;
24455 Roo.data.DataReader.prototype = {
24458 readerType : 'Data',
24460 * Create an empty record
24461 * @param {Object} data (optional) - overlay some values
24462 * @return {Roo.data.Record} record created.
24464 newRow : function(d) {
24466 this.recordType.prototype.fields.each(function(c) {
24468 case 'int' : da[c.name] = 0; break;
24469 case 'date' : da[c.name] = new Date(); break;
24470 case 'float' : da[c.name] = 0.0; break;
24471 case 'boolean' : da[c.name] = false; break;
24472 default : da[c.name] = ""; break;
24476 return new this.recordType(Roo.apply(da, d));
24482 * Ext JS Library 1.1.1
24483 * Copyright(c) 2006-2007, Ext JS, LLC.
24485 * Originally Released Under LGPL - original licence link has changed is not relivant.
24488 * <script type="text/javascript">
24492 * @class Roo.data.DataProxy
24493 * @extends Roo.util.Observable
24495 * This class is an abstract base class for implementations which provide retrieval of
24496 * unformatted data objects.<br>
24498 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24499 * (of the appropriate type which knows how to parse the data object) to provide a block of
24500 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24502 * Custom implementations must implement the load method as described in
24503 * {@link Roo.data.HttpProxy#load}.
24505 Roo.data.DataProxy = function(){
24508 * @event beforeload
24509 * Fires before a network request is made to retrieve a data object.
24510 * @param {Object} This DataProxy object.
24511 * @param {Object} params The params parameter to the load function.
24516 * Fires before the load method's callback is called.
24517 * @param {Object} This DataProxy object.
24518 * @param {Object} o The data object.
24519 * @param {Object} arg The callback argument object passed to the load function.
24523 * @event loadexception
24524 * Fires if an Exception occurs during data retrieval.
24525 * @param {Object} This DataProxy object.
24526 * @param {Object} o The data object.
24527 * @param {Object} arg The callback argument object passed to the load function.
24528 * @param {Object} e The Exception.
24530 loadexception : true
24532 Roo.data.DataProxy.superclass.constructor.call(this);
24535 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24538 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24542 * Ext JS Library 1.1.1
24543 * Copyright(c) 2006-2007, Ext JS, LLC.
24545 * Originally Released Under LGPL - original licence link has changed is not relivant.
24548 * <script type="text/javascript">
24551 * @class Roo.data.MemoryProxy
24552 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24553 * to the Reader when its load method is called.
24555 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24557 Roo.data.MemoryProxy = function(data){
24561 Roo.data.MemoryProxy.superclass.constructor.call(this);
24565 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24568 * Load data from the requested source (in this case an in-memory
24569 * data object passed to the constructor), read the data object into
24570 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24571 * process that block using the passed callback.
24572 * @param {Object} params This parameter is not used by the MemoryProxy class.
24573 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24574 * object into a block of Roo.data.Records.
24575 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24576 * The function must be passed <ul>
24577 * <li>The Record block object</li>
24578 * <li>The "arg" argument from the load function</li>
24579 * <li>A boolean success indicator</li>
24581 * @param {Object} scope The scope in which to call the callback
24582 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24584 load : function(params, reader, callback, scope, arg){
24585 params = params || {};
24588 result = reader.readRecords(params.data ? params.data :this.data);
24590 this.fireEvent("loadexception", this, arg, null, e);
24591 callback.call(scope, null, arg, false);
24594 callback.call(scope, result, arg, true);
24598 update : function(params, records){
24603 * Ext JS Library 1.1.1
24604 * Copyright(c) 2006-2007, Ext JS, LLC.
24606 * Originally Released Under LGPL - original licence link has changed is not relivant.
24609 * <script type="text/javascript">
24612 * @class Roo.data.HttpProxy
24613 * @extends Roo.data.DataProxy
24614 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24615 * configured to reference a certain URL.<br><br>
24617 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24618 * from which the running page was served.<br><br>
24620 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24622 * Be aware that to enable the browser to parse an XML document, the server must set
24623 * the Content-Type header in the HTTP response to "text/xml".
24625 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24626 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24627 * will be used to make the request.
24629 Roo.data.HttpProxy = function(conn){
24630 Roo.data.HttpProxy.superclass.constructor.call(this);
24631 // is conn a conn config or a real conn?
24633 this.useAjax = !conn || !conn.events;
24637 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24638 // thse are take from connection...
24641 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24644 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24645 * extra parameters to each request made by this object. (defaults to undefined)
24648 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24649 * to each request made by this object. (defaults to undefined)
24652 * @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)
24655 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24658 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24664 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24668 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24669 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24670 * a finer-grained basis than the DataProxy events.
24672 getConnection : function(){
24673 return this.useAjax ? Roo.Ajax : this.conn;
24677 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24678 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24679 * process that block using the passed callback.
24680 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24681 * for the request to the remote server.
24682 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24683 * object into a block of Roo.data.Records.
24684 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24685 * The function must be passed <ul>
24686 * <li>The Record block object</li>
24687 * <li>The "arg" argument from the load function</li>
24688 * <li>A boolean success indicator</li>
24690 * @param {Object} scope The scope in which to call the callback
24691 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24693 load : function(params, reader, callback, scope, arg){
24694 if(this.fireEvent("beforeload", this, params) !== false){
24696 params : params || {},
24698 callback : callback,
24703 callback : this.loadResponse,
24707 Roo.applyIf(o, this.conn);
24708 if(this.activeRequest){
24709 Roo.Ajax.abort(this.activeRequest);
24711 this.activeRequest = Roo.Ajax.request(o);
24713 this.conn.request(o);
24716 callback.call(scope||this, null, arg, false);
24721 loadResponse : function(o, success, response){
24722 delete this.activeRequest;
24724 this.fireEvent("loadexception", this, o, response);
24725 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24730 result = o.reader.read(response);
24732 this.fireEvent("loadexception", this, o, response, e);
24733 o.request.callback.call(o.request.scope, {
24736 errorMsg : response.responseText
24739 }, o.request.arg, false);
24743 this.fireEvent("load", this, o, o.request.arg);
24744 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24748 update : function(dataSet){
24753 updateResponse : function(dataSet){
24758 * Ext JS Library 1.1.1
24759 * Copyright(c) 2006-2007, Ext JS, LLC.
24761 * Originally Released Under LGPL - original licence link has changed is not relivant.
24764 * <script type="text/javascript">
24768 * @class Roo.data.ScriptTagProxy
24769 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24770 * other than the originating domain of the running page.<br><br>
24772 * <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
24773 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24775 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24776 * source code that is used as the source inside a <script> tag.<br><br>
24778 * In order for the browser to process the returned data, the server must wrap the data object
24779 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24780 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24781 * depending on whether the callback name was passed:
24784 boolean scriptTag = false;
24785 String cb = request.getParameter("callback");
24788 response.setContentType("text/javascript");
24790 response.setContentType("application/x-json");
24792 Writer out = response.getWriter();
24794 out.write(cb + "(");
24796 out.print(dataBlock.toJsonString());
24803 * @param {Object} config A configuration object.
24805 Roo.data.ScriptTagProxy = function(config){
24806 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24807 Roo.apply(this, config);
24808 this.head = document.getElementsByTagName("head")[0];
24811 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24813 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24815 * @cfg {String} url The URL from which to request the data object.
24818 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24822 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24823 * the server the name of the callback function set up by the load call to process the returned data object.
24824 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24825 * javascript output which calls this named function passing the data object as its only parameter.
24827 callbackParam : "callback",
24829 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24830 * name to the request.
24835 * Load data from the configured URL, read the data object into
24836 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24837 * process that block using the passed callback.
24838 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24839 * for the request to the remote server.
24840 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24841 * object into a block of Roo.data.Records.
24842 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24843 * The function must be passed <ul>
24844 * <li>The Record block object</li>
24845 * <li>The "arg" argument from the load function</li>
24846 * <li>A boolean success indicator</li>
24848 * @param {Object} scope The scope in which to call the callback
24849 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24851 load : function(params, reader, callback, scope, arg){
24852 if(this.fireEvent("beforeload", this, params) !== false){
24854 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24856 var url = this.url;
24857 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24859 url += "&_dc=" + (new Date().getTime());
24861 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24864 cb : "stcCallback"+transId,
24865 scriptId : "stcScript"+transId,
24869 callback : callback,
24875 window[trans.cb] = function(o){
24876 conn.handleResponse(o, trans);
24879 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24881 if(this.autoAbort !== false){
24885 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24887 var script = document.createElement("script");
24888 script.setAttribute("src", url);
24889 script.setAttribute("type", "text/javascript");
24890 script.setAttribute("id", trans.scriptId);
24891 this.head.appendChild(script);
24893 this.trans = trans;
24895 callback.call(scope||this, null, arg, false);
24900 isLoading : function(){
24901 return this.trans ? true : false;
24905 * Abort the current server request.
24907 abort : function(){
24908 if(this.isLoading()){
24909 this.destroyTrans(this.trans);
24914 destroyTrans : function(trans, isLoaded){
24915 this.head.removeChild(document.getElementById(trans.scriptId));
24916 clearTimeout(trans.timeoutId);
24918 window[trans.cb] = undefined;
24920 delete window[trans.cb];
24923 // if hasn't been loaded, wait for load to remove it to prevent script error
24924 window[trans.cb] = function(){
24925 window[trans.cb] = undefined;
24927 delete window[trans.cb];
24934 handleResponse : function(o, trans){
24935 this.trans = false;
24936 this.destroyTrans(trans, true);
24939 result = trans.reader.readRecords(o);
24941 this.fireEvent("loadexception", this, o, trans.arg, e);
24942 trans.callback.call(trans.scope||window, null, trans.arg, false);
24945 this.fireEvent("load", this, o, trans.arg);
24946 trans.callback.call(trans.scope||window, result, trans.arg, true);
24950 handleFailure : function(trans){
24951 this.trans = false;
24952 this.destroyTrans(trans, false);
24953 this.fireEvent("loadexception", this, null, trans.arg);
24954 trans.callback.call(trans.scope||window, null, trans.arg, false);
24958 * Ext JS Library 1.1.1
24959 * Copyright(c) 2006-2007, Ext JS, LLC.
24961 * Originally Released Under LGPL - original licence link has changed is not relivant.
24964 * <script type="text/javascript">
24968 * @class Roo.data.JsonReader
24969 * @extends Roo.data.DataReader
24970 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24971 * based on mappings in a provided Roo.data.Record constructor.
24973 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24974 * in the reply previously.
24979 var RecordDef = Roo.data.Record.create([
24980 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24981 {name: 'occupation'} // This field will use "occupation" as the mapping.
24983 var myReader = new Roo.data.JsonReader({
24984 totalProperty: "results", // The property which contains the total dataset size (optional)
24985 root: "rows", // The property which contains an Array of row objects
24986 id: "id" // The property within each row object that provides an ID for the record (optional)
24990 * This would consume a JSON file like this:
24992 { 'results': 2, 'rows': [
24993 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24994 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24997 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24998 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24999 * paged from the remote server.
25000 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
25001 * @cfg {String} root name of the property which contains the Array of row objects.
25002 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25003 * @cfg {Array} fields Array of field definition objects
25005 * Create a new JsonReader
25006 * @param {Object} meta Metadata configuration options
25007 * @param {Object} recordType Either an Array of field definition objects,
25008 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
25010 Roo.data.JsonReader = function(meta, recordType){
25013 // set some defaults:
25014 Roo.applyIf(meta, {
25015 totalProperty: 'total',
25016 successProperty : 'success',
25021 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25023 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
25025 readerType : 'Json',
25028 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
25029 * Used by Store query builder to append _requestMeta to params.
25032 metaFromRemote : false,
25034 * This method is only used by a DataProxy which has retrieved data from a remote server.
25035 * @param {Object} response The XHR object which contains the JSON data in its responseText.
25036 * @return {Object} data A data block which is used by an Roo.data.Store object as
25037 * a cache of Roo.data.Records.
25039 read : function(response){
25040 var json = response.responseText;
25042 var o = /* eval:var:o */ eval("("+json+")");
25044 throw {message: "JsonReader.read: Json object not found"};
25050 this.metaFromRemote = true;
25051 this.meta = o.metaData;
25052 this.recordType = Roo.data.Record.create(o.metaData.fields);
25053 this.onMetaChange(this.meta, this.recordType, o);
25055 return this.readRecords(o);
25058 // private function a store will implement
25059 onMetaChange : function(meta, recordType, o){
25066 simpleAccess: function(obj, subsc) {
25073 getJsonAccessor: function(){
25075 return function(expr) {
25077 return(re.test(expr))
25078 ? new Function("obj", "return obj." + expr)
25083 return Roo.emptyFn;
25088 * Create a data block containing Roo.data.Records from an XML document.
25089 * @param {Object} o An object which contains an Array of row objects in the property specified
25090 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
25091 * which contains the total size of the dataset.
25092 * @return {Object} data A data block which is used by an Roo.data.Store object as
25093 * a cache of Roo.data.Records.
25095 readRecords : function(o){
25097 * After any data loads, the raw JSON data is available for further custom processing.
25101 var s = this.meta, Record = this.recordType,
25102 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
25104 // Generate extraction functions for the totalProperty, the root, the id, and for each field
25106 if(s.totalProperty) {
25107 this.getTotal = this.getJsonAccessor(s.totalProperty);
25109 if(s.successProperty) {
25110 this.getSuccess = this.getJsonAccessor(s.successProperty);
25112 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
25114 var g = this.getJsonAccessor(s.id);
25115 this.getId = function(rec) {
25117 return (r === undefined || r === "") ? null : r;
25120 this.getId = function(){return null;};
25123 for(var jj = 0; jj < fl; jj++){
25125 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
25126 this.ef[jj] = this.getJsonAccessor(map);
25130 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
25131 if(s.totalProperty){
25132 var vt = parseInt(this.getTotal(o), 10);
25137 if(s.successProperty){
25138 var vs = this.getSuccess(o);
25139 if(vs === false || vs === 'false'){
25144 for(var i = 0; i < c; i++){
25147 var id = this.getId(n);
25148 for(var j = 0; j < fl; j++){
25150 var v = this.ef[j](n);
25152 Roo.log('missing convert for ' + f.name);
25156 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25158 var record = new Record(values, id);
25160 records[i] = record;
25166 totalRecords : totalRecords
25169 // used when loading children.. @see loadDataFromChildren
25170 toLoadData: function(rec)
25172 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25173 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25174 return { data : data, total : data.length };
25179 * Ext JS Library 1.1.1
25180 * Copyright(c) 2006-2007, Ext JS, LLC.
25182 * Originally Released Under LGPL - original licence link has changed is not relivant.
25185 * <script type="text/javascript">
25189 * @class Roo.data.XmlReader
25190 * @extends Roo.data.DataReader
25191 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25192 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25194 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25195 * header in the HTTP response must be set to "text/xml".</em>
25199 var RecordDef = Roo.data.Record.create([
25200 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25201 {name: 'occupation'} // This field will use "occupation" as the mapping.
25203 var myReader = new Roo.data.XmlReader({
25204 totalRecords: "results", // The element which contains the total dataset size (optional)
25205 record: "row", // The repeated element which contains row information
25206 id: "id" // The element within the row that provides an ID for the record (optional)
25210 * This would consume an XML file like this:
25214 <results>2</results>
25217 <name>Bill</name>
25218 <occupation>Gardener</occupation>
25222 <name>Ben</name>
25223 <occupation>Horticulturalist</occupation>
25227 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25228 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25229 * paged from the remote server.
25230 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25231 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25232 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25233 * a record identifier value.
25235 * Create a new XmlReader
25236 * @param {Object} meta Metadata configuration options
25237 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25238 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25239 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25241 Roo.data.XmlReader = function(meta, recordType){
25243 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25245 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25247 readerType : 'Xml',
25250 * This method is only used by a DataProxy which has retrieved data from a remote server.
25251 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25252 * to contain a method called 'responseXML' that returns an XML document object.
25253 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25254 * a cache of Roo.data.Records.
25256 read : function(response){
25257 var doc = response.responseXML;
25259 throw {message: "XmlReader.read: XML Document not available"};
25261 return this.readRecords(doc);
25265 * Create a data block containing Roo.data.Records from an XML document.
25266 * @param {Object} doc A parsed XML document.
25267 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25268 * a cache of Roo.data.Records.
25270 readRecords : function(doc){
25272 * After any data loads/reads, the raw XML Document is available for further custom processing.
25273 * @type XMLDocument
25275 this.xmlData = doc;
25276 var root = doc.documentElement || doc;
25277 var q = Roo.DomQuery;
25278 var recordType = this.recordType, fields = recordType.prototype.fields;
25279 var sid = this.meta.id;
25280 var totalRecords = 0, success = true;
25281 if(this.meta.totalRecords){
25282 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25285 if(this.meta.success){
25286 var sv = q.selectValue(this.meta.success, root, true);
25287 success = sv !== false && sv !== 'false';
25290 var ns = q.select(this.meta.record, root);
25291 for(var i = 0, len = ns.length; i < len; i++) {
25294 var id = sid ? q.selectValue(sid, n) : undefined;
25295 for(var j = 0, jlen = fields.length; j < jlen; j++){
25296 var f = fields.items[j];
25297 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25299 values[f.name] = v;
25301 var record = new recordType(values, id);
25303 records[records.length] = record;
25309 totalRecords : totalRecords || records.length
25314 * Ext JS Library 1.1.1
25315 * Copyright(c) 2006-2007, Ext JS, LLC.
25317 * Originally Released Under LGPL - original licence link has changed is not relivant.
25320 * <script type="text/javascript">
25324 * @class Roo.data.ArrayReader
25325 * @extends Roo.data.DataReader
25326 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25327 * Each element of that Array represents a row of data fields. The
25328 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25329 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25333 var RecordDef = Roo.data.Record.create([
25334 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25335 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25337 var myReader = new Roo.data.ArrayReader({
25338 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25342 * This would consume an Array like this:
25344 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25348 * Create a new JsonReader
25349 * @param {Object} meta Metadata configuration options.
25350 * @param {Object|Array} recordType Either an Array of field definition objects
25352 * @cfg {Array} fields Array of field definition objects
25353 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25354 * as specified to {@link Roo.data.Record#create},
25355 * or an {@link Roo.data.Record} object
25358 * created using {@link Roo.data.Record#create}.
25360 Roo.data.ArrayReader = function(meta, recordType)
25362 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25365 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25368 * Create a data block containing Roo.data.Records from an XML document.
25369 * @param {Object} o An Array of row objects which represents the dataset.
25370 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25371 * a cache of Roo.data.Records.
25373 readRecords : function(o)
25375 var sid = this.meta ? this.meta.id : null;
25376 var recordType = this.recordType, fields = recordType.prototype.fields;
25379 for(var i = 0; i < root.length; i++){
25382 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25383 for(var j = 0, jlen = fields.length; j < jlen; j++){
25384 var f = fields.items[j];
25385 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25386 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25388 values[f.name] = v;
25390 var record = new recordType(values, id);
25392 records[records.length] = record;
25396 totalRecords : records.length
25399 // used when loading children.. @see loadDataFromChildren
25400 toLoadData: function(rec)
25402 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25403 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25410 * Ext JS Library 1.1.1
25411 * Copyright(c) 2006-2007, Ext JS, LLC.
25413 * Originally Released Under LGPL - original licence link has changed is not relivant.
25416 * <script type="text/javascript">
25421 * @class Roo.data.Tree
25422 * @extends Roo.util.Observable
25423 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25424 * in the tree have most standard DOM functionality.
25426 * @param {Node} root (optional) The root node
25428 Roo.data.Tree = function(root){
25429 this.nodeHash = {};
25431 * The root node for this tree
25436 this.setRootNode(root);
25441 * Fires when a new child node is appended to a node in this tree.
25442 * @param {Tree} tree The owner tree
25443 * @param {Node} parent The parent node
25444 * @param {Node} node The newly appended node
25445 * @param {Number} index The index of the newly appended node
25450 * Fires when a child node is removed from a node in this tree.
25451 * @param {Tree} tree The owner tree
25452 * @param {Node} parent The parent node
25453 * @param {Node} node The child node removed
25458 * Fires when a node is moved to a new location in the tree
25459 * @param {Tree} tree The owner tree
25460 * @param {Node} node The node moved
25461 * @param {Node} oldParent The old parent of this node
25462 * @param {Node} newParent The new parent of this node
25463 * @param {Number} index The index it was moved to
25468 * Fires when a new child node is inserted in a node in this tree.
25469 * @param {Tree} tree The owner tree
25470 * @param {Node} parent The parent node
25471 * @param {Node} node The child node inserted
25472 * @param {Node} refNode The child node the node was inserted before
25476 * @event beforeappend
25477 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25478 * @param {Tree} tree The owner tree
25479 * @param {Node} parent The parent node
25480 * @param {Node} node The child node to be appended
25482 "beforeappend" : true,
25484 * @event beforeremove
25485 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25486 * @param {Tree} tree The owner tree
25487 * @param {Node} parent The parent node
25488 * @param {Node} node The child node to be removed
25490 "beforeremove" : true,
25492 * @event beforemove
25493 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25494 * @param {Tree} tree The owner tree
25495 * @param {Node} node The node being moved
25496 * @param {Node} oldParent The parent of the node
25497 * @param {Node} newParent The new parent the node is moving to
25498 * @param {Number} index The index it is being moved to
25500 "beforemove" : true,
25502 * @event beforeinsert
25503 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25504 * @param {Tree} tree The owner tree
25505 * @param {Node} parent The parent node
25506 * @param {Node} node The child node to be inserted
25507 * @param {Node} refNode The child node the node is being inserted before
25509 "beforeinsert" : true
25512 Roo.data.Tree.superclass.constructor.call(this);
25515 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25516 pathSeparator: "/",
25518 proxyNodeEvent : function(){
25519 return this.fireEvent.apply(this, arguments);
25523 * Returns the root node for this tree.
25526 getRootNode : function(){
25531 * Sets the root node for this tree.
25532 * @param {Node} node
25535 setRootNode : function(node){
25537 node.ownerTree = this;
25538 node.isRoot = true;
25539 this.registerNode(node);
25544 * Gets a node in this tree by its id.
25545 * @param {String} id
25548 getNodeById : function(id){
25549 return this.nodeHash[id];
25552 registerNode : function(node){
25553 this.nodeHash[node.id] = node;
25556 unregisterNode : function(node){
25557 delete this.nodeHash[node.id];
25560 toString : function(){
25561 return "[Tree"+(this.id?" "+this.id:"")+"]";
25566 * @class Roo.data.Node
25567 * @extends Roo.util.Observable
25568 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25569 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25571 * @param {Object} attributes The attributes/config for the node
25573 Roo.data.Node = function(attributes){
25575 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25578 this.attributes = attributes || {};
25579 this.leaf = this.attributes.leaf;
25581 * The node id. @type String
25583 this.id = this.attributes.id;
25585 this.id = Roo.id(null, "ynode-");
25586 this.attributes.id = this.id;
25591 * All child nodes of this node. @type Array
25593 this.childNodes = [];
25594 if(!this.childNodes.indexOf){ // indexOf is a must
25595 this.childNodes.indexOf = function(o){
25596 for(var i = 0, len = this.length; i < len; i++){
25605 * The parent node for this node. @type Node
25607 this.parentNode = null;
25609 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25611 this.firstChild = null;
25613 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25615 this.lastChild = null;
25617 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25619 this.previousSibling = null;
25621 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25623 this.nextSibling = null;
25628 * Fires when a new child node is appended
25629 * @param {Tree} tree The owner tree
25630 * @param {Node} this This node
25631 * @param {Node} node The newly appended node
25632 * @param {Number} index The index of the newly appended node
25637 * Fires when a child node is removed
25638 * @param {Tree} tree The owner tree
25639 * @param {Node} this This node
25640 * @param {Node} node The removed node
25645 * Fires when this node is moved to a new location in the tree
25646 * @param {Tree} tree The owner tree
25647 * @param {Node} this This node
25648 * @param {Node} oldParent The old parent of this node
25649 * @param {Node} newParent The new parent of this node
25650 * @param {Number} index The index it was moved to
25655 * Fires when a new child node is inserted.
25656 * @param {Tree} tree The owner tree
25657 * @param {Node} this This node
25658 * @param {Node} node The child node inserted
25659 * @param {Node} refNode The child node the node was inserted before
25663 * @event beforeappend
25664 * Fires before a new child is appended, return false to cancel the append.
25665 * @param {Tree} tree The owner tree
25666 * @param {Node} this This node
25667 * @param {Node} node The child node to be appended
25669 "beforeappend" : true,
25671 * @event beforeremove
25672 * Fires before a child is removed, return false to cancel the remove.
25673 * @param {Tree} tree The owner tree
25674 * @param {Node} this This node
25675 * @param {Node} node The child node to be removed
25677 "beforeremove" : true,
25679 * @event beforemove
25680 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25681 * @param {Tree} tree The owner tree
25682 * @param {Node} this This node
25683 * @param {Node} oldParent The parent of this node
25684 * @param {Node} newParent The new parent this node is moving to
25685 * @param {Number} index The index it is being moved to
25687 "beforemove" : true,
25689 * @event beforeinsert
25690 * Fires before a new child is inserted, return false to cancel the insert.
25691 * @param {Tree} tree The owner tree
25692 * @param {Node} this This node
25693 * @param {Node} node The child node to be inserted
25694 * @param {Node} refNode The child node the node is being inserted before
25696 "beforeinsert" : true
25698 this.listeners = this.attributes.listeners;
25699 Roo.data.Node.superclass.constructor.call(this);
25702 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25703 fireEvent : function(evtName){
25704 // first do standard event for this node
25705 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25708 // then bubble it up to the tree if the event wasn't cancelled
25709 var ot = this.getOwnerTree();
25711 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25719 * Returns true if this node is a leaf
25720 * @return {Boolean}
25722 isLeaf : function(){
25723 return this.leaf === true;
25727 setFirstChild : function(node){
25728 this.firstChild = node;
25732 setLastChild : function(node){
25733 this.lastChild = node;
25738 * Returns true if this node is the last child of its parent
25739 * @return {Boolean}
25741 isLast : function(){
25742 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25746 * Returns true if this node is the first child of its parent
25747 * @return {Boolean}
25749 isFirst : function(){
25750 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25753 hasChildNodes : function(){
25754 return !this.isLeaf() && this.childNodes.length > 0;
25758 * Insert node(s) as the last child node of this node.
25759 * @param {Node/Array} node The node or Array of nodes to append
25760 * @return {Node} The appended node if single append, or null if an array was passed
25762 appendChild : function(node){
25764 if(node instanceof Array){
25766 }else if(arguments.length > 1){
25770 // if passed an array or multiple args do them one by one
25772 for(var i = 0, len = multi.length; i < len; i++) {
25773 this.appendChild(multi[i]);
25776 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25779 var index = this.childNodes.length;
25780 var oldParent = node.parentNode;
25781 // it's a move, make sure we move it cleanly
25783 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25786 oldParent.removeChild(node);
25789 index = this.childNodes.length;
25791 this.setFirstChild(node);
25793 this.childNodes.push(node);
25794 node.parentNode = this;
25795 var ps = this.childNodes[index-1];
25797 node.previousSibling = ps;
25798 ps.nextSibling = node;
25800 node.previousSibling = null;
25802 node.nextSibling = null;
25803 this.setLastChild(node);
25804 node.setOwnerTree(this.getOwnerTree());
25805 this.fireEvent("append", this.ownerTree, this, node, index);
25806 if(this.ownerTree) {
25807 this.ownerTree.fireEvent("appendnode", this, node, index);
25810 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25817 * Removes a child node from this node.
25818 * @param {Node} node The node to remove
25819 * @return {Node} The removed node
25821 removeChild : function(node){
25822 var index = this.childNodes.indexOf(node);
25826 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25830 // remove it from childNodes collection
25831 this.childNodes.splice(index, 1);
25834 if(node.previousSibling){
25835 node.previousSibling.nextSibling = node.nextSibling;
25837 if(node.nextSibling){
25838 node.nextSibling.previousSibling = node.previousSibling;
25841 // update child refs
25842 if(this.firstChild == node){
25843 this.setFirstChild(node.nextSibling);
25845 if(this.lastChild == node){
25846 this.setLastChild(node.previousSibling);
25849 node.setOwnerTree(null);
25850 // clear any references from the node
25851 node.parentNode = null;
25852 node.previousSibling = null;
25853 node.nextSibling = null;
25854 this.fireEvent("remove", this.ownerTree, this, node);
25859 * Inserts the first node before the second node in this nodes childNodes collection.
25860 * @param {Node} node The node to insert
25861 * @param {Node} refNode The node to insert before (if null the node is appended)
25862 * @return {Node} The inserted node
25864 insertBefore : function(node, refNode){
25865 if(!refNode){ // like standard Dom, refNode can be null for append
25866 return this.appendChild(node);
25869 if(node == refNode){
25873 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25876 var index = this.childNodes.indexOf(refNode);
25877 var oldParent = node.parentNode;
25878 var refIndex = index;
25880 // when moving internally, indexes will change after remove
25881 if(oldParent == this && this.childNodes.indexOf(node) < index){
25885 // it's a move, make sure we move it cleanly
25887 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25890 oldParent.removeChild(node);
25893 this.setFirstChild(node);
25895 this.childNodes.splice(refIndex, 0, node);
25896 node.parentNode = this;
25897 var ps = this.childNodes[refIndex-1];
25899 node.previousSibling = ps;
25900 ps.nextSibling = node;
25902 node.previousSibling = null;
25904 node.nextSibling = refNode;
25905 refNode.previousSibling = node;
25906 node.setOwnerTree(this.getOwnerTree());
25907 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25909 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25915 * Returns the child node at the specified index.
25916 * @param {Number} index
25919 item : function(index){
25920 return this.childNodes[index];
25924 * Replaces one child node in this node with another.
25925 * @param {Node} newChild The replacement node
25926 * @param {Node} oldChild The node to replace
25927 * @return {Node} The replaced node
25929 replaceChild : function(newChild, oldChild){
25930 this.insertBefore(newChild, oldChild);
25931 this.removeChild(oldChild);
25936 * Returns the index of a child node
25937 * @param {Node} node
25938 * @return {Number} The index of the node or -1 if it was not found
25940 indexOf : function(child){
25941 return this.childNodes.indexOf(child);
25945 * Returns the tree this node is in.
25948 getOwnerTree : function(){
25949 // if it doesn't have one, look for one
25950 if(!this.ownerTree){
25954 this.ownerTree = p.ownerTree;
25960 return this.ownerTree;
25964 * Returns depth of this node (the root node has a depth of 0)
25967 getDepth : function(){
25970 while(p.parentNode){
25978 setOwnerTree : function(tree){
25979 // if it's move, we need to update everyone
25980 if(tree != this.ownerTree){
25981 if(this.ownerTree){
25982 this.ownerTree.unregisterNode(this);
25984 this.ownerTree = tree;
25985 var cs = this.childNodes;
25986 for(var i = 0, len = cs.length; i < len; i++) {
25987 cs[i].setOwnerTree(tree);
25990 tree.registerNode(this);
25996 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25997 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25998 * @return {String} The path
26000 getPath : function(attr){
26001 attr = attr || "id";
26002 var p = this.parentNode;
26003 var b = [this.attributes[attr]];
26005 b.unshift(p.attributes[attr]);
26008 var sep = this.getOwnerTree().pathSeparator;
26009 return sep + b.join(sep);
26013 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26014 * function call will be the scope provided or the current node. The arguments to the function
26015 * will be the args provided or the current node. If the function returns false at any point,
26016 * the bubble is stopped.
26017 * @param {Function} fn The function to call
26018 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26019 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26021 bubble : function(fn, scope, args){
26024 if(fn.call(scope || p, args || p) === false){
26032 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26033 * function call will be the scope provided or the current node. The arguments to the function
26034 * will be the args provided or the current node. If the function returns false at any point,
26035 * the cascade is stopped on that branch.
26036 * @param {Function} fn The function to call
26037 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26038 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26040 cascade : function(fn, scope, args){
26041 if(fn.call(scope || this, args || this) !== false){
26042 var cs = this.childNodes;
26043 for(var i = 0, len = cs.length; i < len; i++) {
26044 cs[i].cascade(fn, scope, args);
26050 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
26051 * function call will be the scope provided or the current node. The arguments to the function
26052 * will be the args provided or the current node. If the function returns false at any point,
26053 * the iteration stops.
26054 * @param {Function} fn The function to call
26055 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26056 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26058 eachChild : function(fn, scope, args){
26059 var cs = this.childNodes;
26060 for(var i = 0, len = cs.length; i < len; i++) {
26061 if(fn.call(scope || this, args || cs[i]) === false){
26068 * Finds the first child that has the attribute with the specified value.
26069 * @param {String} attribute The attribute name
26070 * @param {Mixed} value The value to search for
26071 * @return {Node} The found child or null if none was found
26073 findChild : function(attribute, value){
26074 var cs = this.childNodes;
26075 for(var i = 0, len = cs.length; i < len; i++) {
26076 if(cs[i].attributes[attribute] == value){
26084 * Finds the first child by a custom function. The child matches if the function passed
26086 * @param {Function} fn
26087 * @param {Object} scope (optional)
26088 * @return {Node} The found child or null if none was found
26090 findChildBy : function(fn, scope){
26091 var cs = this.childNodes;
26092 for(var i = 0, len = cs.length; i < len; i++) {
26093 if(fn.call(scope||cs[i], cs[i]) === true){
26101 * Sorts this nodes children using the supplied sort function
26102 * @param {Function} fn
26103 * @param {Object} scope (optional)
26105 sort : function(fn, scope){
26106 var cs = this.childNodes;
26107 var len = cs.length;
26109 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
26111 for(var i = 0; i < len; i++){
26113 n.previousSibling = cs[i-1];
26114 n.nextSibling = cs[i+1];
26116 this.setFirstChild(n);
26119 this.setLastChild(n);
26126 * Returns true if this node is an ancestor (at any point) of the passed node.
26127 * @param {Node} node
26128 * @return {Boolean}
26130 contains : function(node){
26131 return node.isAncestor(this);
26135 * Returns true if the passed node is an ancestor (at any point) of this node.
26136 * @param {Node} node
26137 * @return {Boolean}
26139 isAncestor : function(node){
26140 var p = this.parentNode;
26150 toString : function(){
26151 return "[Node"+(this.id?" "+this.id:"")+"]";
26155 * Ext JS Library 1.1.1
26156 * Copyright(c) 2006-2007, Ext JS, LLC.
26158 * Originally Released Under LGPL - original licence link has changed is not relivant.
26161 * <script type="text/javascript">
26166 * @class Roo.Shadow
26167 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26168 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26169 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26171 * Create a new Shadow
26172 * @param {Object} config The config object
26174 Roo.Shadow = function(config){
26175 Roo.apply(this, config);
26176 if(typeof this.mode != "string"){
26177 this.mode = this.defaultMode;
26179 var o = this.offset, a = {h: 0};
26180 var rad = Math.floor(this.offset/2);
26181 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26187 a.l -= this.offset + rad;
26188 a.t -= this.offset + rad;
26199 a.l -= (this.offset - rad);
26200 a.t -= this.offset + rad;
26202 a.w -= (this.offset - rad)*2;
26213 a.l -= (this.offset - rad);
26214 a.t -= (this.offset - rad);
26216 a.w -= (this.offset + rad + 1);
26217 a.h -= (this.offset + rad);
26226 Roo.Shadow.prototype = {
26228 * @cfg {String} mode
26229 * The shadow display mode. Supports the following options:<br />
26230 * sides: Shadow displays on both sides and bottom only<br />
26231 * frame: Shadow displays equally on all four sides<br />
26232 * drop: Traditional bottom-right drop shadow (default)
26236 * @cfg {String} offset
26237 * The number of pixels to offset the shadow from the element (defaults to 4)
26242 defaultMode: "drop",
26245 * Displays the shadow under the target element
26246 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26248 show : function(target){
26249 target = Roo.get(target);
26251 this.el = Roo.Shadow.Pool.pull();
26252 if(this.el.dom.nextSibling != target.dom){
26253 this.el.insertBefore(target);
26256 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26258 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26261 target.getLeft(true),
26262 target.getTop(true),
26266 this.el.dom.style.display = "block";
26270 * Returns true if the shadow is visible, else false
26272 isVisible : function(){
26273 return this.el ? true : false;
26277 * Direct alignment when values are already available. Show must be called at least once before
26278 * calling this method to ensure it is initialized.
26279 * @param {Number} left The target element left position
26280 * @param {Number} top The target element top position
26281 * @param {Number} width The target element width
26282 * @param {Number} height The target element height
26284 realign : function(l, t, w, h){
26288 var a = this.adjusts, d = this.el.dom, s = d.style;
26290 s.left = (l+a.l)+"px";
26291 s.top = (t+a.t)+"px";
26292 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26294 if(s.width != sws || s.height != shs){
26298 var cn = d.childNodes;
26299 var sww = Math.max(0, (sw-12))+"px";
26300 cn[0].childNodes[1].style.width = sww;
26301 cn[1].childNodes[1].style.width = sww;
26302 cn[2].childNodes[1].style.width = sww;
26303 cn[1].style.height = Math.max(0, (sh-12))+"px";
26309 * Hides this shadow
26313 this.el.dom.style.display = "none";
26314 Roo.Shadow.Pool.push(this.el);
26320 * Adjust the z-index of this shadow
26321 * @param {Number} zindex The new z-index
26323 setZIndex : function(z){
26326 this.el.setStyle("z-index", z);
26331 // Private utility class that manages the internal Shadow cache
26332 Roo.Shadow.Pool = function(){
26334 var markup = Roo.isIE ?
26335 '<div class="x-ie-shadow"></div>' :
26336 '<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>';
26339 var sh = p.shift();
26341 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26342 sh.autoBoxAdjust = false;
26347 push : function(sh){
26353 * Ext JS Library 1.1.1
26354 * Copyright(c) 2006-2007, Ext JS, LLC.
26356 * Originally Released Under LGPL - original licence link has changed is not relivant.
26359 * <script type="text/javascript">
26364 * @class Roo.SplitBar
26365 * @extends Roo.util.Observable
26366 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26370 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26371 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26372 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26373 split.minSize = 100;
26374 split.maxSize = 600;
26375 split.animate = true;
26376 split.on('moved', splitterMoved);
26379 * Create a new SplitBar
26380 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26381 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26382 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26383 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26384 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26385 position of the SplitBar).
26387 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26390 this.el = Roo.get(dragElement, true);
26391 this.el.dom.unselectable = "on";
26393 this.resizingEl = Roo.get(resizingElement, true);
26397 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26398 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26401 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26404 * The minimum size of the resizing element. (Defaults to 0)
26410 * The maximum size of the resizing element. (Defaults to 2000)
26413 this.maxSize = 2000;
26416 * Whether to animate the transition to the new size
26419 this.animate = false;
26422 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26425 this.useShim = false;
26430 if(!existingProxy){
26432 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26434 this.proxy = Roo.get(existingProxy).dom;
26437 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26440 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26443 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26446 this.dragSpecs = {};
26449 * @private The adapter to use to positon and resize elements
26451 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26452 this.adapter.init(this);
26454 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26456 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26457 this.el.addClass("x-splitbar-h");
26460 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26461 this.el.addClass("x-splitbar-v");
26467 * Fires when the splitter is moved (alias for {@link #event-moved})
26468 * @param {Roo.SplitBar} this
26469 * @param {Number} newSize the new width or height
26474 * Fires when the splitter is moved
26475 * @param {Roo.SplitBar} this
26476 * @param {Number} newSize the new width or height
26480 * @event beforeresize
26481 * Fires before the splitter is dragged
26482 * @param {Roo.SplitBar} this
26484 "beforeresize" : true,
26486 "beforeapply" : true
26489 Roo.util.Observable.call(this);
26492 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26493 onStartProxyDrag : function(x, y){
26494 this.fireEvent("beforeresize", this);
26496 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26498 o.enableDisplayMode("block");
26499 // all splitbars share the same overlay
26500 Roo.SplitBar.prototype.overlay = o;
26502 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26503 this.overlay.show();
26504 Roo.get(this.proxy).setDisplayed("block");
26505 var size = this.adapter.getElementSize(this);
26506 this.activeMinSize = this.getMinimumSize();;
26507 this.activeMaxSize = this.getMaximumSize();;
26508 var c1 = size - this.activeMinSize;
26509 var c2 = Math.max(this.activeMaxSize - size, 0);
26510 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26511 this.dd.resetConstraints();
26512 this.dd.setXConstraint(
26513 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26514 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26516 this.dd.setYConstraint(0, 0);
26518 this.dd.resetConstraints();
26519 this.dd.setXConstraint(0, 0);
26520 this.dd.setYConstraint(
26521 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26522 this.placement == Roo.SplitBar.TOP ? c2 : c1
26525 this.dragSpecs.startSize = size;
26526 this.dragSpecs.startPoint = [x, y];
26527 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26531 * @private Called after the drag operation by the DDProxy
26533 onEndProxyDrag : function(e){
26534 Roo.get(this.proxy).setDisplayed(false);
26535 var endPoint = Roo.lib.Event.getXY(e);
26537 this.overlay.hide();
26540 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26541 newSize = this.dragSpecs.startSize +
26542 (this.placement == Roo.SplitBar.LEFT ?
26543 endPoint[0] - this.dragSpecs.startPoint[0] :
26544 this.dragSpecs.startPoint[0] - endPoint[0]
26547 newSize = this.dragSpecs.startSize +
26548 (this.placement == Roo.SplitBar.TOP ?
26549 endPoint[1] - this.dragSpecs.startPoint[1] :
26550 this.dragSpecs.startPoint[1] - endPoint[1]
26553 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26554 if(newSize != this.dragSpecs.startSize){
26555 if(this.fireEvent('beforeapply', this, newSize) !== false){
26556 this.adapter.setElementSize(this, newSize);
26557 this.fireEvent("moved", this, newSize);
26558 this.fireEvent("resize", this, newSize);
26564 * Get the adapter this SplitBar uses
26565 * @return The adapter object
26567 getAdapter : function(){
26568 return this.adapter;
26572 * Set the adapter this SplitBar uses
26573 * @param {Object} adapter A SplitBar adapter object
26575 setAdapter : function(adapter){
26576 this.adapter = adapter;
26577 this.adapter.init(this);
26581 * Gets the minimum size for the resizing element
26582 * @return {Number} The minimum size
26584 getMinimumSize : function(){
26585 return this.minSize;
26589 * Sets the minimum size for the resizing element
26590 * @param {Number} minSize The minimum size
26592 setMinimumSize : function(minSize){
26593 this.minSize = minSize;
26597 * Gets the maximum size for the resizing element
26598 * @return {Number} The maximum size
26600 getMaximumSize : function(){
26601 return this.maxSize;
26605 * Sets the maximum size for the resizing element
26606 * @param {Number} maxSize The maximum size
26608 setMaximumSize : function(maxSize){
26609 this.maxSize = maxSize;
26613 * Sets the initialize size for the resizing element
26614 * @param {Number} size The initial size
26616 setCurrentSize : function(size){
26617 var oldAnimate = this.animate;
26618 this.animate = false;
26619 this.adapter.setElementSize(this, size);
26620 this.animate = oldAnimate;
26624 * Destroy this splitbar.
26625 * @param {Boolean} removeEl True to remove the element
26627 destroy : function(removeEl){
26629 this.shim.remove();
26632 this.proxy.parentNode.removeChild(this.proxy);
26640 * @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.
26642 Roo.SplitBar.createProxy = function(dir){
26643 var proxy = new Roo.Element(document.createElement("div"));
26644 proxy.unselectable();
26645 var cls = 'x-splitbar-proxy';
26646 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26647 document.body.appendChild(proxy.dom);
26652 * @class Roo.SplitBar.BasicLayoutAdapter
26653 * Default Adapter. It assumes the splitter and resizing element are not positioned
26654 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26656 Roo.SplitBar.BasicLayoutAdapter = function(){
26659 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26660 // do nothing for now
26661 init : function(s){
26665 * Called before drag operations to get the current size of the resizing element.
26666 * @param {Roo.SplitBar} s The SplitBar using this adapter
26668 getElementSize : function(s){
26669 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26670 return s.resizingEl.getWidth();
26672 return s.resizingEl.getHeight();
26677 * Called after drag operations to set the size of the resizing element.
26678 * @param {Roo.SplitBar} s The SplitBar using this adapter
26679 * @param {Number} newSize The new size to set
26680 * @param {Function} onComplete A function to be invoked when resizing is complete
26682 setElementSize : function(s, newSize, onComplete){
26683 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26685 s.resizingEl.setWidth(newSize);
26687 onComplete(s, newSize);
26690 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26695 s.resizingEl.setHeight(newSize);
26697 onComplete(s, newSize);
26700 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26707 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26708 * @extends Roo.SplitBar.BasicLayoutAdapter
26709 * Adapter that moves the splitter element to align with the resized sizing element.
26710 * Used with an absolute positioned SplitBar.
26711 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26712 * document.body, make sure you assign an id to the body element.
26714 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26715 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26716 this.container = Roo.get(container);
26719 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26720 init : function(s){
26721 this.basic.init(s);
26724 getElementSize : function(s){
26725 return this.basic.getElementSize(s);
26728 setElementSize : function(s, newSize, onComplete){
26729 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26732 moveSplitter : function(s){
26733 var yes = Roo.SplitBar;
26734 switch(s.placement){
26736 s.el.setX(s.resizingEl.getRight());
26739 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26742 s.el.setY(s.resizingEl.getBottom());
26745 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26752 * Orientation constant - Create a vertical SplitBar
26756 Roo.SplitBar.VERTICAL = 1;
26759 * Orientation constant - Create a horizontal SplitBar
26763 Roo.SplitBar.HORIZONTAL = 2;
26766 * Placement constant - The resizing element is to the left of the splitter element
26770 Roo.SplitBar.LEFT = 1;
26773 * Placement constant - The resizing element is to the right of the splitter element
26777 Roo.SplitBar.RIGHT = 2;
26780 * Placement constant - The resizing element is positioned above the splitter element
26784 Roo.SplitBar.TOP = 3;
26787 * Placement constant - The resizing element is positioned under splitter element
26791 Roo.SplitBar.BOTTOM = 4;
26794 * Ext JS Library 1.1.1
26795 * Copyright(c) 2006-2007, Ext JS, LLC.
26797 * Originally Released Under LGPL - original licence link has changed is not relivant.
26800 * <script type="text/javascript">
26805 * @extends Roo.util.Observable
26806 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26807 * This class also supports single and multi selection modes. <br>
26808 * Create a data model bound view:
26810 var store = new Roo.data.Store(...);
26812 var view = new Roo.View({
26814 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26816 singleSelect: true,
26817 selectedClass: "ydataview-selected",
26821 // listen for node click?
26822 view.on("click", function(vw, index, node, e){
26823 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26827 dataModel.load("foobar.xml");
26829 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26831 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26832 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26834 * Note: old style constructor is still suported (container, template, config)
26837 * Create a new View
26838 * @param {Object} config The config object
26841 Roo.View = function(config, depreciated_tpl, depreciated_config){
26843 this.parent = false;
26845 if (typeof(depreciated_tpl) == 'undefined') {
26846 // new way.. - universal constructor.
26847 Roo.apply(this, config);
26848 this.el = Roo.get(this.el);
26851 this.el = Roo.get(config);
26852 this.tpl = depreciated_tpl;
26853 Roo.apply(this, depreciated_config);
26855 this.wrapEl = this.el.wrap().wrap();
26856 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26859 if(typeof(this.tpl) == "string"){
26860 this.tpl = new Roo.Template(this.tpl);
26862 // support xtype ctors..
26863 this.tpl = new Roo.factory(this.tpl, Roo);
26867 this.tpl.compile();
26872 * @event beforeclick
26873 * Fires before a click is processed. Returns false to cancel the default action.
26874 * @param {Roo.View} this
26875 * @param {Number} index The index of the target node
26876 * @param {HTMLElement} node The target node
26877 * @param {Roo.EventObject} e The raw event object
26879 "beforeclick" : true,
26882 * Fires when a template node is clicked.
26883 * @param {Roo.View} this
26884 * @param {Number} index The index of the target node
26885 * @param {HTMLElement} node The target node
26886 * @param {Roo.EventObject} e The raw event object
26891 * Fires when a template node is double clicked.
26892 * @param {Roo.View} this
26893 * @param {Number} index The index of the target node
26894 * @param {HTMLElement} node The target node
26895 * @param {Roo.EventObject} e The raw event object
26899 * @event contextmenu
26900 * Fires when a template node is right clicked.
26901 * @param {Roo.View} this
26902 * @param {Number} index The index of the target node
26903 * @param {HTMLElement} node The target node
26904 * @param {Roo.EventObject} e The raw event object
26906 "contextmenu" : true,
26908 * @event selectionchange
26909 * Fires when the selected nodes change.
26910 * @param {Roo.View} this
26911 * @param {Array} selections Array of the selected nodes
26913 "selectionchange" : true,
26916 * @event beforeselect
26917 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26918 * @param {Roo.View} this
26919 * @param {HTMLElement} node The node to be selected
26920 * @param {Array} selections Array of currently selected nodes
26922 "beforeselect" : true,
26924 * @event preparedata
26925 * Fires on every row to render, to allow you to change the data.
26926 * @param {Roo.View} this
26927 * @param {Object} data to be rendered (change this)
26929 "preparedata" : true
26937 "click": this.onClick,
26938 "dblclick": this.onDblClick,
26939 "contextmenu": this.onContextMenu,
26943 this.selections = [];
26945 this.cmp = new Roo.CompositeElementLite([]);
26947 this.store = Roo.factory(this.store, Roo.data);
26948 this.setStore(this.store, true);
26951 if ( this.footer && this.footer.xtype) {
26953 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26955 this.footer.dataSource = this.store;
26956 this.footer.container = fctr;
26957 this.footer = Roo.factory(this.footer, Roo);
26958 fctr.insertFirst(this.el);
26960 // this is a bit insane - as the paging toolbar seems to detach the el..
26961 // dom.parentNode.parentNode.parentNode
26962 // they get detached?
26966 Roo.View.superclass.constructor.call(this);
26971 Roo.extend(Roo.View, Roo.util.Observable, {
26974 * @cfg {Roo.data.Store} store Data store to load data from.
26979 * @cfg {String|Roo.Element} el The container element.
26984 * @cfg {String|Roo.Template} tpl The template used by this View
26988 * @cfg {String} dataName the named area of the template to use as the data area
26989 * Works with domtemplates roo-name="name"
26993 * @cfg {String} selectedClass The css class to add to selected nodes
26995 selectedClass : "x-view-selected",
26997 * @cfg {String} emptyText The empty text to show when nothing is loaded.
27002 * @cfg {String} text to display on mask (default Loading)
27006 * @cfg {Boolean} multiSelect Allow multiple selection
27008 multiSelect : false,
27010 * @cfg {Boolean} singleSelect Allow single selection
27012 singleSelect: false,
27015 * @cfg {Boolean} toggleSelect - selecting
27017 toggleSelect : false,
27020 * @cfg {Boolean} tickable - selecting
27025 * Returns the element this view is bound to.
27026 * @return {Roo.Element}
27028 getEl : function(){
27029 return this.wrapEl;
27035 * Refreshes the view. - called by datachanged on the store. - do not call directly.
27037 refresh : function(){
27038 //Roo.log('refresh');
27041 // if we are using something like 'domtemplate', then
27042 // the what gets used is:
27043 // t.applySubtemplate(NAME, data, wrapping data..)
27044 // the outer template then get' applied with
27045 // the store 'extra data'
27046 // and the body get's added to the
27047 // roo-name="data" node?
27048 // <span class='roo-tpl-{name}'></span> ?????
27052 this.clearSelections();
27053 this.el.update("");
27055 var records = this.store.getRange();
27056 if(records.length < 1) {
27058 // is this valid?? = should it render a template??
27060 this.el.update(this.emptyText);
27064 if (this.dataName) {
27065 this.el.update(t.apply(this.store.meta)); //????
27066 el = this.el.child('.roo-tpl-' + this.dataName);
27069 for(var i = 0, len = records.length; i < len; i++){
27070 var data = this.prepareData(records[i].data, i, records[i]);
27071 this.fireEvent("preparedata", this, data, i, records[i]);
27073 var d = Roo.apply({}, data);
27076 Roo.apply(d, {'roo-id' : Roo.id()});
27080 Roo.each(this.parent.item, function(item){
27081 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
27084 Roo.apply(d, {'roo-data-checked' : 'checked'});
27088 html[html.length] = Roo.util.Format.trim(
27090 t.applySubtemplate(this.dataName, d, this.store.meta) :
27097 el.update(html.join(""));
27098 this.nodes = el.dom.childNodes;
27099 this.updateIndexes(0);
27104 * Function to override to reformat the data that is sent to
27105 * the template for each node.
27106 * DEPRICATED - use the preparedata event handler.
27107 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
27108 * a JSON object for an UpdateManager bound view).
27110 prepareData : function(data, index, record)
27112 this.fireEvent("preparedata", this, data, index, record);
27116 onUpdate : function(ds, record){
27117 // Roo.log('on update');
27118 this.clearSelections();
27119 var index = this.store.indexOf(record);
27120 var n = this.nodes[index];
27121 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
27122 n.parentNode.removeChild(n);
27123 this.updateIndexes(index, index);
27129 onAdd : function(ds, records, index)
27131 //Roo.log(['on Add', ds, records, index] );
27132 this.clearSelections();
27133 if(this.nodes.length == 0){
27137 var n = this.nodes[index];
27138 for(var i = 0, len = records.length; i < len; i++){
27139 var d = this.prepareData(records[i].data, i, records[i]);
27141 this.tpl.insertBefore(n, d);
27144 this.tpl.append(this.el, d);
27147 this.updateIndexes(index);
27150 onRemove : function(ds, record, index){
27151 // Roo.log('onRemove');
27152 this.clearSelections();
27153 var el = this.dataName ?
27154 this.el.child('.roo-tpl-' + this.dataName) :
27157 el.dom.removeChild(this.nodes[index]);
27158 this.updateIndexes(index);
27162 * Refresh an individual node.
27163 * @param {Number} index
27165 refreshNode : function(index){
27166 this.onUpdate(this.store, this.store.getAt(index));
27169 updateIndexes : function(startIndex, endIndex){
27170 var ns = this.nodes;
27171 startIndex = startIndex || 0;
27172 endIndex = endIndex || ns.length - 1;
27173 for(var i = startIndex; i <= endIndex; i++){
27174 ns[i].nodeIndex = i;
27179 * Changes the data store this view uses and refresh the view.
27180 * @param {Store} store
27182 setStore : function(store, initial){
27183 if(!initial && this.store){
27184 this.store.un("datachanged", this.refresh);
27185 this.store.un("add", this.onAdd);
27186 this.store.un("remove", this.onRemove);
27187 this.store.un("update", this.onUpdate);
27188 this.store.un("clear", this.refresh);
27189 this.store.un("beforeload", this.onBeforeLoad);
27190 this.store.un("load", this.onLoad);
27191 this.store.un("loadexception", this.onLoad);
27195 store.on("datachanged", this.refresh, this);
27196 store.on("add", this.onAdd, this);
27197 store.on("remove", this.onRemove, this);
27198 store.on("update", this.onUpdate, this);
27199 store.on("clear", this.refresh, this);
27200 store.on("beforeload", this.onBeforeLoad, this);
27201 store.on("load", this.onLoad, this);
27202 store.on("loadexception", this.onLoad, this);
27210 * onbeforeLoad - masks the loading area.
27213 onBeforeLoad : function(store,opts)
27215 //Roo.log('onBeforeLoad');
27217 this.el.update("");
27219 this.el.mask(this.mask ? this.mask : "Loading" );
27221 onLoad : function ()
27228 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27229 * @param {HTMLElement} node
27230 * @return {HTMLElement} The template node
27232 findItemFromChild : function(node){
27233 var el = this.dataName ?
27234 this.el.child('.roo-tpl-' + this.dataName,true) :
27237 if(!node || node.parentNode == el){
27240 var p = node.parentNode;
27241 while(p && p != el){
27242 if(p.parentNode == el){
27251 onClick : function(e){
27252 var item = this.findItemFromChild(e.getTarget());
27254 var index = this.indexOf(item);
27255 if(this.onItemClick(item, index, e) !== false){
27256 this.fireEvent("click", this, index, item, e);
27259 this.clearSelections();
27264 onContextMenu : function(e){
27265 var item = this.findItemFromChild(e.getTarget());
27267 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27272 onDblClick : function(e){
27273 var item = this.findItemFromChild(e.getTarget());
27275 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27279 onItemClick : function(item, index, e)
27281 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27284 if (this.toggleSelect) {
27285 var m = this.isSelected(item) ? 'unselect' : 'select';
27288 _t[m](item, true, false);
27291 if(this.multiSelect || this.singleSelect){
27292 if(this.multiSelect && e.shiftKey && this.lastSelection){
27293 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27295 this.select(item, this.multiSelect && e.ctrlKey);
27296 this.lastSelection = item;
27299 if(!this.tickable){
27300 e.preventDefault();
27308 * Get the number of selected nodes.
27311 getSelectionCount : function(){
27312 return this.selections.length;
27316 * Get the currently selected nodes.
27317 * @return {Array} An array of HTMLElements
27319 getSelectedNodes : function(){
27320 return this.selections;
27324 * Get the indexes of the selected nodes.
27327 getSelectedIndexes : function(){
27328 var indexes = [], s = this.selections;
27329 for(var i = 0, len = s.length; i < len; i++){
27330 indexes.push(s[i].nodeIndex);
27336 * Clear all selections
27337 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27339 clearSelections : function(suppressEvent){
27340 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27341 this.cmp.elements = this.selections;
27342 this.cmp.removeClass(this.selectedClass);
27343 this.selections = [];
27344 if(!suppressEvent){
27345 this.fireEvent("selectionchange", this, this.selections);
27351 * Returns true if the passed node is selected
27352 * @param {HTMLElement/Number} node The node or node index
27353 * @return {Boolean}
27355 isSelected : function(node){
27356 var s = this.selections;
27360 node = this.getNode(node);
27361 return s.indexOf(node) !== -1;
27366 * @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
27367 * @param {Boolean} keepExisting (optional) true to keep existing selections
27368 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27370 select : function(nodeInfo, keepExisting, suppressEvent){
27371 if(nodeInfo instanceof Array){
27373 this.clearSelections(true);
27375 for(var i = 0, len = nodeInfo.length; i < len; i++){
27376 this.select(nodeInfo[i], true, true);
27380 var node = this.getNode(nodeInfo);
27381 if(!node || this.isSelected(node)){
27382 return; // already selected.
27385 this.clearSelections(true);
27388 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27389 Roo.fly(node).addClass(this.selectedClass);
27390 this.selections.push(node);
27391 if(!suppressEvent){
27392 this.fireEvent("selectionchange", this, this.selections);
27400 * @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
27401 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27402 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27404 unselect : function(nodeInfo, keepExisting, suppressEvent)
27406 if(nodeInfo instanceof Array){
27407 Roo.each(this.selections, function(s) {
27408 this.unselect(s, nodeInfo);
27412 var node = this.getNode(nodeInfo);
27413 if(!node || !this.isSelected(node)){
27414 //Roo.log("not selected");
27415 return; // not selected.
27419 Roo.each(this.selections, function(s) {
27421 Roo.fly(node).removeClass(this.selectedClass);
27428 this.selections= ns;
27429 this.fireEvent("selectionchange", this, this.selections);
27433 * Gets a template node.
27434 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27435 * @return {HTMLElement} The node or null if it wasn't found
27437 getNode : function(nodeInfo){
27438 if(typeof nodeInfo == "string"){
27439 return document.getElementById(nodeInfo);
27440 }else if(typeof nodeInfo == "number"){
27441 return this.nodes[nodeInfo];
27447 * Gets a range template nodes.
27448 * @param {Number} startIndex
27449 * @param {Number} endIndex
27450 * @return {Array} An array of nodes
27452 getNodes : function(start, end){
27453 var ns = this.nodes;
27454 start = start || 0;
27455 end = typeof end == "undefined" ? ns.length - 1 : end;
27458 for(var i = start; i <= end; i++){
27462 for(var i = start; i >= end; i--){
27470 * Finds the index of the passed node
27471 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27472 * @return {Number} The index of the node or -1
27474 indexOf : function(node){
27475 node = this.getNode(node);
27476 if(typeof node.nodeIndex == "number"){
27477 return node.nodeIndex;
27479 var ns = this.nodes;
27480 for(var i = 0, len = ns.length; i < len; i++){
27490 * Ext JS Library 1.1.1
27491 * Copyright(c) 2006-2007, Ext JS, LLC.
27493 * Originally Released Under LGPL - original licence link has changed is not relivant.
27496 * <script type="text/javascript">
27500 * @class Roo.JsonView
27501 * @extends Roo.View
27502 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27504 var view = new Roo.JsonView({
27505 container: "my-element",
27506 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27511 // listen for node click?
27512 view.on("click", function(vw, index, node, e){
27513 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27516 // direct load of JSON data
27517 view.load("foobar.php");
27519 // Example from my blog list
27520 var tpl = new Roo.Template(
27521 '<div class="entry">' +
27522 '<a class="entry-title" href="{link}">{title}</a>' +
27523 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27524 "</div><hr />"
27527 var moreView = new Roo.JsonView({
27528 container : "entry-list",
27532 moreView.on("beforerender", this.sortEntries, this);
27534 url: "/blog/get-posts.php",
27535 params: "allposts=true",
27536 text: "Loading Blog Entries..."
27540 * Note: old code is supported with arguments : (container, template, config)
27544 * Create a new JsonView
27546 * @param {Object} config The config object
27549 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27552 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27554 var um = this.el.getUpdateManager();
27555 um.setRenderer(this);
27556 um.on("update", this.onLoad, this);
27557 um.on("failure", this.onLoadException, this);
27560 * @event beforerender
27561 * Fires before rendering of the downloaded JSON data.
27562 * @param {Roo.JsonView} this
27563 * @param {Object} data The JSON data loaded
27567 * Fires when data is loaded.
27568 * @param {Roo.JsonView} this
27569 * @param {Object} data The JSON data loaded
27570 * @param {Object} response The raw Connect response object
27573 * @event loadexception
27574 * Fires when loading fails.
27575 * @param {Roo.JsonView} this
27576 * @param {Object} response The raw Connect response object
27579 'beforerender' : true,
27581 'loadexception' : true
27584 Roo.extend(Roo.JsonView, Roo.View, {
27586 * @type {String} The root property in the loaded JSON object that contains the data
27591 * Refreshes the view.
27593 refresh : function(){
27594 this.clearSelections();
27595 this.el.update("");
27597 var o = this.jsonData;
27598 if(o && o.length > 0){
27599 for(var i = 0, len = o.length; i < len; i++){
27600 var data = this.prepareData(o[i], i, o);
27601 html[html.length] = this.tpl.apply(data);
27604 html.push(this.emptyText);
27606 this.el.update(html.join(""));
27607 this.nodes = this.el.dom.childNodes;
27608 this.updateIndexes(0);
27612 * 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.
27613 * @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:
27616 url: "your-url.php",
27617 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27618 callback: yourFunction,
27619 scope: yourObject, //(optional scope)
27622 text: "Loading...",
27627 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27628 * 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.
27629 * @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}
27630 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27631 * @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.
27634 var um = this.el.getUpdateManager();
27635 um.update.apply(um, arguments);
27638 // note - render is a standard framework call...
27639 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27640 render : function(el, response){
27642 this.clearSelections();
27643 this.el.update("");
27646 if (response != '') {
27647 o = Roo.util.JSON.decode(response.responseText);
27650 o = o[this.jsonRoot];
27656 * The current JSON data or null
27659 this.beforeRender();
27664 * Get the number of records in the current JSON dataset
27667 getCount : function(){
27668 return this.jsonData ? this.jsonData.length : 0;
27672 * Returns the JSON object for the specified node(s)
27673 * @param {HTMLElement/Array} node The node or an array of nodes
27674 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27675 * you get the JSON object for the node
27677 getNodeData : function(node){
27678 if(node instanceof Array){
27680 for(var i = 0, len = node.length; i < len; i++){
27681 data.push(this.getNodeData(node[i]));
27685 return this.jsonData[this.indexOf(node)] || null;
27688 beforeRender : function(){
27689 this.snapshot = this.jsonData;
27691 this.sort.apply(this, this.sortInfo);
27693 this.fireEvent("beforerender", this, this.jsonData);
27696 onLoad : function(el, o){
27697 this.fireEvent("load", this, this.jsonData, o);
27700 onLoadException : function(el, o){
27701 this.fireEvent("loadexception", this, o);
27705 * Filter the data by a specific property.
27706 * @param {String} property A property on your JSON objects
27707 * @param {String/RegExp} value Either string that the property values
27708 * should start with, or a RegExp to test against the property
27710 filter : function(property, value){
27713 var ss = this.snapshot;
27714 if(typeof value == "string"){
27715 var vlen = value.length;
27717 this.clearFilter();
27720 value = value.toLowerCase();
27721 for(var i = 0, len = ss.length; i < len; i++){
27723 if(o[property].substr(0, vlen).toLowerCase() == value){
27727 } else if(value.exec){ // regex?
27728 for(var i = 0, len = ss.length; i < len; i++){
27730 if(value.test(o[property])){
27737 this.jsonData = data;
27743 * Filter by a function. The passed function will be called with each
27744 * object in the current dataset. If the function returns true the value is kept,
27745 * otherwise it is filtered.
27746 * @param {Function} fn
27747 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27749 filterBy : function(fn, scope){
27752 var ss = this.snapshot;
27753 for(var i = 0, len = ss.length; i < len; i++){
27755 if(fn.call(scope || this, o)){
27759 this.jsonData = data;
27765 * Clears the current filter.
27767 clearFilter : function(){
27768 if(this.snapshot && this.jsonData != this.snapshot){
27769 this.jsonData = this.snapshot;
27776 * Sorts the data for this view and refreshes it.
27777 * @param {String} property A property on your JSON objects to sort on
27778 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27779 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27781 sort : function(property, dir, sortType){
27782 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27785 var dsc = dir && dir.toLowerCase() == "desc";
27786 var f = function(o1, o2){
27787 var v1 = sortType ? sortType(o1[p]) : o1[p];
27788 var v2 = sortType ? sortType(o2[p]) : o2[p];
27791 return dsc ? +1 : -1;
27792 } else if(v1 > v2){
27793 return dsc ? -1 : +1;
27798 this.jsonData.sort(f);
27800 if(this.jsonData != this.snapshot){
27801 this.snapshot.sort(f);
27807 * Ext JS Library 1.1.1
27808 * Copyright(c) 2006-2007, Ext JS, LLC.
27810 * Originally Released Under LGPL - original licence link has changed is not relivant.
27813 * <script type="text/javascript">
27818 * @class Roo.ColorPalette
27819 * @extends Roo.Component
27820 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27821 * Here's an example of typical usage:
27823 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27824 cp.render('my-div');
27826 cp.on('select', function(palette, selColor){
27827 // do something with selColor
27831 * Create a new ColorPalette
27832 * @param {Object} config The config object
27834 Roo.ColorPalette = function(config){
27835 Roo.ColorPalette.superclass.constructor.call(this, config);
27839 * Fires when a color is selected
27840 * @param {ColorPalette} this
27841 * @param {String} color The 6-digit color hex code (without the # symbol)
27847 this.on("select", this.handler, this.scope, true);
27850 Roo.extend(Roo.ColorPalette, Roo.Component, {
27852 * @cfg {String} itemCls
27853 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27855 itemCls : "x-color-palette",
27857 * @cfg {String} value
27858 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27859 * the hex codes are case-sensitive.
27862 clickEvent:'click',
27864 ctype: "Roo.ColorPalette",
27867 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27869 allowReselect : false,
27872 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27873 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27874 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27875 * of colors with the width setting until the box is symmetrical.</p>
27876 * <p>You can override individual colors if needed:</p>
27878 var cp = new Roo.ColorPalette();
27879 cp.colors[0] = "FF0000"; // change the first box to red
27882 Or you can provide a custom array of your own for complete control:
27884 var cp = new Roo.ColorPalette();
27885 cp.colors = ["000000", "993300", "333300"];
27890 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27891 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27892 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27893 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27894 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27898 onRender : function(container, position){
27899 var t = new Roo.MasterTemplate(
27900 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27902 var c = this.colors;
27903 for(var i = 0, len = c.length; i < len; i++){
27906 var el = document.createElement("div");
27907 el.className = this.itemCls;
27909 container.dom.insertBefore(el, position);
27910 this.el = Roo.get(el);
27911 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27912 if(this.clickEvent != 'click'){
27913 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27918 afterRender : function(){
27919 Roo.ColorPalette.superclass.afterRender.call(this);
27921 var s = this.value;
27928 handleClick : function(e, t){
27929 e.preventDefault();
27930 if(!this.disabled){
27931 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27932 this.select(c.toUpperCase());
27937 * Selects the specified color in the palette (fires the select event)
27938 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27940 select : function(color){
27941 color = color.replace("#", "");
27942 if(color != this.value || this.allowReselect){
27945 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27947 el.child("a.color-"+color).addClass("x-color-palette-sel");
27948 this.value = color;
27949 this.fireEvent("select", this, color);
27954 * Ext JS Library 1.1.1
27955 * Copyright(c) 2006-2007, Ext JS, LLC.
27957 * Originally Released Under LGPL - original licence link has changed is not relivant.
27960 * <script type="text/javascript">
27964 * @class Roo.DatePicker
27965 * @extends Roo.Component
27966 * Simple date picker class.
27968 * Create a new DatePicker
27969 * @param {Object} config The config object
27971 Roo.DatePicker = function(config){
27972 Roo.DatePicker.superclass.constructor.call(this, config);
27974 this.value = config && config.value ?
27975 config.value.clearTime() : new Date().clearTime();
27980 * Fires when a date is selected
27981 * @param {DatePicker} this
27982 * @param {Date} date The selected date
27986 * @event monthchange
27987 * Fires when the displayed month changes
27988 * @param {DatePicker} this
27989 * @param {Date} date The selected month
27991 'monthchange': true
27995 this.on("select", this.handler, this.scope || this);
27997 // build the disabledDatesRE
27998 if(!this.disabledDatesRE && this.disabledDates){
27999 var dd = this.disabledDates;
28001 for(var i = 0; i < dd.length; i++){
28003 if(i != dd.length-1) {
28007 this.disabledDatesRE = new RegExp(re + ")");
28011 Roo.extend(Roo.DatePicker, Roo.Component, {
28013 * @cfg {String} todayText
28014 * The text to display on the button that selects the current date (defaults to "Today")
28016 todayText : "Today",
28018 * @cfg {String} okText
28019 * The text to display on the ok button
28021 okText : " OK ", //   to give the user extra clicking room
28023 * @cfg {String} cancelText
28024 * The text to display on the cancel button
28026 cancelText : "Cancel",
28028 * @cfg {String} todayTip
28029 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
28031 todayTip : "{0} (Spacebar)",
28033 * @cfg {Date} minDate
28034 * Minimum allowable date (JavaScript date object, defaults to null)
28038 * @cfg {Date} maxDate
28039 * Maximum allowable date (JavaScript date object, defaults to null)
28043 * @cfg {String} minText
28044 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
28046 minText : "This date is before the minimum date",
28048 * @cfg {String} maxText
28049 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
28051 maxText : "This date is after the maximum date",
28053 * @cfg {String} format
28054 * The default date format string which can be overriden for localization support. The format must be
28055 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
28059 * @cfg {Array} disabledDays
28060 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
28062 disabledDays : null,
28064 * @cfg {String} disabledDaysText
28065 * The tooltip to display when the date falls on a disabled day (defaults to "")
28067 disabledDaysText : "",
28069 * @cfg {RegExp} disabledDatesRE
28070 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
28072 disabledDatesRE : null,
28074 * @cfg {String} disabledDatesText
28075 * The tooltip text to display when the date falls on a disabled date (defaults to "")
28077 disabledDatesText : "",
28079 * @cfg {Boolean} constrainToViewport
28080 * True to constrain the date picker to the viewport (defaults to true)
28082 constrainToViewport : true,
28084 * @cfg {Array} monthNames
28085 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
28087 monthNames : Date.monthNames,
28089 * @cfg {Array} dayNames
28090 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
28092 dayNames : Date.dayNames,
28094 * @cfg {String} nextText
28095 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
28097 nextText: 'Next Month (Control+Right)',
28099 * @cfg {String} prevText
28100 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
28102 prevText: 'Previous Month (Control+Left)',
28104 * @cfg {String} monthYearText
28105 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
28107 monthYearText: 'Choose a month (Control+Up/Down to move years)',
28109 * @cfg {Number} startDay
28110 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
28114 * @cfg {Bool} showClear
28115 * Show a clear button (usefull for date form elements that can be blank.)
28121 * Sets the value of the date field
28122 * @param {Date} value The date to set
28124 setValue : function(value){
28125 var old = this.value;
28127 if (typeof(value) == 'string') {
28129 value = Date.parseDate(value, this.format);
28132 value = new Date();
28135 this.value = value.clearTime(true);
28137 this.update(this.value);
28142 * Gets the current selected value of the date field
28143 * @return {Date} The selected date
28145 getValue : function(){
28150 focus : function(){
28152 this.update(this.activeDate);
28157 onRender : function(container, position){
28160 '<table cellspacing="0">',
28161 '<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>',
28162 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28163 var dn = this.dayNames;
28164 for(var i = 0; i < 7; i++){
28165 var d = this.startDay+i;
28169 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28171 m[m.length] = "</tr></thead><tbody><tr>";
28172 for(var i = 0; i < 42; i++) {
28173 if(i % 7 == 0 && i != 0){
28174 m[m.length] = "</tr><tr>";
28176 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28178 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28179 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28181 var el = document.createElement("div");
28182 el.className = "x-date-picker";
28183 el.innerHTML = m.join("");
28185 container.dom.insertBefore(el, position);
28187 this.el = Roo.get(el);
28188 this.eventEl = Roo.get(el.firstChild);
28190 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28191 handler: this.showPrevMonth,
28193 preventDefault:true,
28197 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28198 handler: this.showNextMonth,
28200 preventDefault:true,
28204 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28206 this.monthPicker = this.el.down('div.x-date-mp');
28207 this.monthPicker.enableDisplayMode('block');
28209 var kn = new Roo.KeyNav(this.eventEl, {
28210 "left" : function(e){
28212 this.showPrevMonth() :
28213 this.update(this.activeDate.add("d", -1));
28216 "right" : function(e){
28218 this.showNextMonth() :
28219 this.update(this.activeDate.add("d", 1));
28222 "up" : function(e){
28224 this.showNextYear() :
28225 this.update(this.activeDate.add("d", -7));
28228 "down" : function(e){
28230 this.showPrevYear() :
28231 this.update(this.activeDate.add("d", 7));
28234 "pageUp" : function(e){
28235 this.showNextMonth();
28238 "pageDown" : function(e){
28239 this.showPrevMonth();
28242 "enter" : function(e){
28243 e.stopPropagation();
28250 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28252 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28254 this.el.unselectable();
28256 this.cells = this.el.select("table.x-date-inner tbody td");
28257 this.textNodes = this.el.query("table.x-date-inner tbody span");
28259 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28261 tooltip: this.monthYearText
28264 this.mbtn.on('click', this.showMonthPicker, this);
28265 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28268 var today = (new Date()).dateFormat(this.format);
28270 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28271 if (this.showClear) {
28272 baseTb.add( new Roo.Toolbar.Fill());
28275 text: String.format(this.todayText, today),
28276 tooltip: String.format(this.todayTip, today),
28277 handler: this.selectToday,
28281 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28284 if (this.showClear) {
28286 baseTb.add( new Roo.Toolbar.Fill());
28289 cls: 'x-btn-icon x-btn-clear',
28290 handler: function() {
28292 this.fireEvent("select", this, '');
28302 this.update(this.value);
28305 createMonthPicker : function(){
28306 if(!this.monthPicker.dom.firstChild){
28307 var buf = ['<table border="0" cellspacing="0">'];
28308 for(var i = 0; i < 6; i++){
28310 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28311 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28313 '<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>' :
28314 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28318 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28320 '</button><button type="button" class="x-date-mp-cancel">',
28322 '</button></td></tr>',
28325 this.monthPicker.update(buf.join(''));
28326 this.monthPicker.on('click', this.onMonthClick, this);
28327 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28329 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28330 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28332 this.mpMonths.each(function(m, a, i){
28335 m.dom.xmonth = 5 + Math.round(i * .5);
28337 m.dom.xmonth = Math.round((i-1) * .5);
28343 showMonthPicker : function(){
28344 this.createMonthPicker();
28345 var size = this.el.getSize();
28346 this.monthPicker.setSize(size);
28347 this.monthPicker.child('table').setSize(size);
28349 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28350 this.updateMPMonth(this.mpSelMonth);
28351 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28352 this.updateMPYear(this.mpSelYear);
28354 this.monthPicker.slideIn('t', {duration:.2});
28357 updateMPYear : function(y){
28359 var ys = this.mpYears.elements;
28360 for(var i = 1; i <= 10; i++){
28361 var td = ys[i-1], y2;
28363 y2 = y + Math.round(i * .5);
28364 td.firstChild.innerHTML = y2;
28367 y2 = y - (5-Math.round(i * .5));
28368 td.firstChild.innerHTML = y2;
28371 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28375 updateMPMonth : function(sm){
28376 this.mpMonths.each(function(m, a, i){
28377 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28381 selectMPMonth: function(m){
28385 onMonthClick : function(e, t){
28387 var el = new Roo.Element(t), pn;
28388 if(el.is('button.x-date-mp-cancel')){
28389 this.hideMonthPicker();
28391 else if(el.is('button.x-date-mp-ok')){
28392 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28393 this.hideMonthPicker();
28395 else if(pn = el.up('td.x-date-mp-month', 2)){
28396 this.mpMonths.removeClass('x-date-mp-sel');
28397 pn.addClass('x-date-mp-sel');
28398 this.mpSelMonth = pn.dom.xmonth;
28400 else if(pn = el.up('td.x-date-mp-year', 2)){
28401 this.mpYears.removeClass('x-date-mp-sel');
28402 pn.addClass('x-date-mp-sel');
28403 this.mpSelYear = pn.dom.xyear;
28405 else if(el.is('a.x-date-mp-prev')){
28406 this.updateMPYear(this.mpyear-10);
28408 else if(el.is('a.x-date-mp-next')){
28409 this.updateMPYear(this.mpyear+10);
28413 onMonthDblClick : function(e, t){
28415 var el = new Roo.Element(t), pn;
28416 if(pn = el.up('td.x-date-mp-month', 2)){
28417 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28418 this.hideMonthPicker();
28420 else if(pn = el.up('td.x-date-mp-year', 2)){
28421 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28422 this.hideMonthPicker();
28426 hideMonthPicker : function(disableAnim){
28427 if(this.monthPicker){
28428 if(disableAnim === true){
28429 this.monthPicker.hide();
28431 this.monthPicker.slideOut('t', {duration:.2});
28437 showPrevMonth : function(e){
28438 this.update(this.activeDate.add("mo", -1));
28442 showNextMonth : function(e){
28443 this.update(this.activeDate.add("mo", 1));
28447 showPrevYear : function(){
28448 this.update(this.activeDate.add("y", -1));
28452 showNextYear : function(){
28453 this.update(this.activeDate.add("y", 1));
28457 handleMouseWheel : function(e){
28458 var delta = e.getWheelDelta();
28460 this.showPrevMonth();
28462 } else if(delta < 0){
28463 this.showNextMonth();
28469 handleDateClick : function(e, t){
28471 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28472 this.setValue(new Date(t.dateValue));
28473 this.fireEvent("select", this, this.value);
28478 selectToday : function(){
28479 this.setValue(new Date().clearTime());
28480 this.fireEvent("select", this, this.value);
28484 update : function(date)
28486 var vd = this.activeDate;
28487 this.activeDate = date;
28489 var t = date.getTime();
28490 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28491 this.cells.removeClass("x-date-selected");
28492 this.cells.each(function(c){
28493 if(c.dom.firstChild.dateValue == t){
28494 c.addClass("x-date-selected");
28495 setTimeout(function(){
28496 try{c.dom.firstChild.focus();}catch(e){}
28505 var days = date.getDaysInMonth();
28506 var firstOfMonth = date.getFirstDateOfMonth();
28507 var startingPos = firstOfMonth.getDay()-this.startDay;
28509 if(startingPos <= this.startDay){
28513 var pm = date.add("mo", -1);
28514 var prevStart = pm.getDaysInMonth()-startingPos;
28516 var cells = this.cells.elements;
28517 var textEls = this.textNodes;
28518 days += startingPos;
28520 // convert everything to numbers so it's fast
28521 var day = 86400000;
28522 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28523 var today = new Date().clearTime().getTime();
28524 var sel = date.clearTime().getTime();
28525 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28526 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28527 var ddMatch = this.disabledDatesRE;
28528 var ddText = this.disabledDatesText;
28529 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28530 var ddaysText = this.disabledDaysText;
28531 var format = this.format;
28533 var setCellClass = function(cal, cell){
28535 var t = d.getTime();
28536 cell.firstChild.dateValue = t;
28538 cell.className += " x-date-today";
28539 cell.title = cal.todayText;
28542 cell.className += " x-date-selected";
28543 setTimeout(function(){
28544 try{cell.firstChild.focus();}catch(e){}
28549 cell.className = " x-date-disabled";
28550 cell.title = cal.minText;
28554 cell.className = " x-date-disabled";
28555 cell.title = cal.maxText;
28559 if(ddays.indexOf(d.getDay()) != -1){
28560 cell.title = ddaysText;
28561 cell.className = " x-date-disabled";
28564 if(ddMatch && format){
28565 var fvalue = d.dateFormat(format);
28566 if(ddMatch.test(fvalue)){
28567 cell.title = ddText.replace("%0", fvalue);
28568 cell.className = " x-date-disabled";
28574 for(; i < startingPos; i++) {
28575 textEls[i].innerHTML = (++prevStart);
28576 d.setDate(d.getDate()+1);
28577 cells[i].className = "x-date-prevday";
28578 setCellClass(this, cells[i]);
28580 for(; i < days; i++){
28581 intDay = i - startingPos + 1;
28582 textEls[i].innerHTML = (intDay);
28583 d.setDate(d.getDate()+1);
28584 cells[i].className = "x-date-active";
28585 setCellClass(this, cells[i]);
28588 for(; i < 42; i++) {
28589 textEls[i].innerHTML = (++extraDays);
28590 d.setDate(d.getDate()+1);
28591 cells[i].className = "x-date-nextday";
28592 setCellClass(this, cells[i]);
28595 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28596 this.fireEvent('monthchange', this, date);
28598 if(!this.internalRender){
28599 var main = this.el.dom.firstChild;
28600 var w = main.offsetWidth;
28601 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28602 Roo.fly(main).setWidth(w);
28603 this.internalRender = true;
28604 // opera does not respect the auto grow header center column
28605 // then, after it gets a width opera refuses to recalculate
28606 // without a second pass
28607 if(Roo.isOpera && !this.secondPass){
28608 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28609 this.secondPass = true;
28610 this.update.defer(10, this, [date]);
28618 * Ext JS Library 1.1.1
28619 * Copyright(c) 2006-2007, Ext JS, LLC.
28621 * Originally Released Under LGPL - original licence link has changed is not relivant.
28624 * <script type="text/javascript">
28627 * @class Roo.TabPanel
28628 * @extends Roo.util.Observable
28629 * A lightweight tab container.
28633 // basic tabs 1, built from existing content
28634 var tabs = new Roo.TabPanel("tabs1");
28635 tabs.addTab("script", "View Script");
28636 tabs.addTab("markup", "View Markup");
28637 tabs.activate("script");
28639 // more advanced tabs, built from javascript
28640 var jtabs = new Roo.TabPanel("jtabs");
28641 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28643 // set up the UpdateManager
28644 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28645 var updater = tab2.getUpdateManager();
28646 updater.setDefaultUrl("ajax1.htm");
28647 tab2.on('activate', updater.refresh, updater, true);
28649 // Use setUrl for Ajax loading
28650 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28651 tab3.setUrl("ajax2.htm", null, true);
28654 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28657 jtabs.activate("jtabs-1");
28660 * Create a new TabPanel.
28661 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28662 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28664 Roo.TabPanel = function(container, config){
28666 * The container element for this TabPanel.
28667 * @type Roo.Element
28669 this.el = Roo.get(container, true);
28671 if(typeof config == "boolean"){
28672 this.tabPosition = config ? "bottom" : "top";
28674 Roo.apply(this, config);
28677 if(this.tabPosition == "bottom"){
28678 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28679 this.el.addClass("x-tabs-bottom");
28681 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28682 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28683 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28685 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28687 if(this.tabPosition != "bottom"){
28688 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28689 * @type Roo.Element
28691 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28692 this.el.addClass("x-tabs-top");
28696 this.bodyEl.setStyle("position", "relative");
28698 this.active = null;
28699 this.activateDelegate = this.activate.createDelegate(this);
28704 * Fires when the active tab changes
28705 * @param {Roo.TabPanel} this
28706 * @param {Roo.TabPanelItem} activePanel The new active tab
28710 * @event beforetabchange
28711 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28712 * @param {Roo.TabPanel} this
28713 * @param {Object} e Set cancel to true on this object to cancel the tab change
28714 * @param {Roo.TabPanelItem} tab The tab being changed to
28716 "beforetabchange" : true
28719 Roo.EventManager.onWindowResize(this.onResize, this);
28720 this.cpad = this.el.getPadding("lr");
28721 this.hiddenCount = 0;
28724 // toolbar on the tabbar support...
28725 if (this.toolbar) {
28726 var tcfg = this.toolbar;
28727 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28728 this.toolbar = new Roo.Toolbar(tcfg);
28729 if (Roo.isSafari) {
28730 var tbl = tcfg.container.child('table', true);
28731 tbl.setAttribute('width', '100%');
28738 Roo.TabPanel.superclass.constructor.call(this);
28741 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28743 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28745 tabPosition : "top",
28747 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28749 currentTabWidth : 0,
28751 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28755 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28759 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28761 preferredTabWidth : 175,
28763 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28765 resizeTabs : false,
28767 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28769 monitorResize : true,
28771 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28776 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28777 * @param {String} id The id of the div to use <b>or create</b>
28778 * @param {String} text The text for the tab
28779 * @param {String} content (optional) Content to put in the TabPanelItem body
28780 * @param {Boolean} closable (optional) True to create a close icon on the tab
28781 * @return {Roo.TabPanelItem} The created TabPanelItem
28783 addTab : function(id, text, content, closable){
28784 var item = new Roo.TabPanelItem(this, id, text, closable);
28785 this.addTabItem(item);
28787 item.setContent(content);
28793 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28794 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28795 * @return {Roo.TabPanelItem}
28797 getTab : function(id){
28798 return this.items[id];
28802 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28803 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28805 hideTab : function(id){
28806 var t = this.items[id];
28809 this.hiddenCount++;
28810 this.autoSizeTabs();
28815 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28816 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28818 unhideTab : function(id){
28819 var t = this.items[id];
28821 t.setHidden(false);
28822 this.hiddenCount--;
28823 this.autoSizeTabs();
28828 * Adds an existing {@link Roo.TabPanelItem}.
28829 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28831 addTabItem : function(item){
28832 this.items[item.id] = item;
28833 this.items.push(item);
28834 if(this.resizeTabs){
28835 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28836 this.autoSizeTabs();
28843 * Removes a {@link Roo.TabPanelItem}.
28844 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28846 removeTab : function(id){
28847 var items = this.items;
28848 var tab = items[id];
28849 if(!tab) { return; }
28850 var index = items.indexOf(tab);
28851 if(this.active == tab && items.length > 1){
28852 var newTab = this.getNextAvailable(index);
28857 this.stripEl.dom.removeChild(tab.pnode.dom);
28858 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28859 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28861 items.splice(index, 1);
28862 delete this.items[tab.id];
28863 tab.fireEvent("close", tab);
28864 tab.purgeListeners();
28865 this.autoSizeTabs();
28868 getNextAvailable : function(start){
28869 var items = this.items;
28871 // look for a next tab that will slide over to
28872 // replace the one being removed
28873 while(index < items.length){
28874 var item = items[++index];
28875 if(item && !item.isHidden()){
28879 // if one isn't found select the previous tab (on the left)
28882 var item = items[--index];
28883 if(item && !item.isHidden()){
28891 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28892 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28894 disableTab : function(id){
28895 var tab = this.items[id];
28896 if(tab && this.active != tab){
28902 * Enables a {@link Roo.TabPanelItem} that is disabled.
28903 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28905 enableTab : function(id){
28906 var tab = this.items[id];
28911 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28912 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28913 * @return {Roo.TabPanelItem} The TabPanelItem.
28915 activate : function(id){
28916 var tab = this.items[id];
28920 if(tab == this.active || tab.disabled){
28924 this.fireEvent("beforetabchange", this, e, tab);
28925 if(e.cancel !== true && !tab.disabled){
28927 this.active.hide();
28929 this.active = this.items[id];
28930 this.active.show();
28931 this.fireEvent("tabchange", this, this.active);
28937 * Gets the active {@link Roo.TabPanelItem}.
28938 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28940 getActiveTab : function(){
28941 return this.active;
28945 * Updates the tab body element to fit the height of the container element
28946 * for overflow scrolling
28947 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28949 syncHeight : function(targetHeight){
28950 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28951 var bm = this.bodyEl.getMargins();
28952 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28953 this.bodyEl.setHeight(newHeight);
28957 onResize : function(){
28958 if(this.monitorResize){
28959 this.autoSizeTabs();
28964 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28966 beginUpdate : function(){
28967 this.updating = true;
28971 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28973 endUpdate : function(){
28974 this.updating = false;
28975 this.autoSizeTabs();
28979 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28981 autoSizeTabs : function(){
28982 var count = this.items.length;
28983 var vcount = count - this.hiddenCount;
28984 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28987 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28988 var availWidth = Math.floor(w / vcount);
28989 var b = this.stripBody;
28990 if(b.getWidth() > w){
28991 var tabs = this.items;
28992 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28993 if(availWidth < this.minTabWidth){
28994 /*if(!this.sleft){ // incomplete scrolling code
28995 this.createScrollButtons();
28998 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
29001 if(this.currentTabWidth < this.preferredTabWidth){
29002 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
29008 * Returns the number of tabs in this TabPanel.
29011 getCount : function(){
29012 return this.items.length;
29016 * Resizes all the tabs to the passed width
29017 * @param {Number} The new width
29019 setTabWidth : function(width){
29020 this.currentTabWidth = width;
29021 for(var i = 0, len = this.items.length; i < len; i++) {
29022 if(!this.items[i].isHidden()) {
29023 this.items[i].setWidth(width);
29029 * Destroys this TabPanel
29030 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
29032 destroy : function(removeEl){
29033 Roo.EventManager.removeResizeListener(this.onResize, this);
29034 for(var i = 0, len = this.items.length; i < len; i++){
29035 this.items[i].purgeListeners();
29037 if(removeEl === true){
29038 this.el.update("");
29045 * @class Roo.TabPanelItem
29046 * @extends Roo.util.Observable
29047 * Represents an individual item (tab plus body) in a TabPanel.
29048 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
29049 * @param {String} id The id of this TabPanelItem
29050 * @param {String} text The text for the tab of this TabPanelItem
29051 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
29053 Roo.TabPanelItem = function(tabPanel, id, text, closable){
29055 * The {@link Roo.TabPanel} this TabPanelItem belongs to
29056 * @type Roo.TabPanel
29058 this.tabPanel = tabPanel;
29060 * The id for this TabPanelItem
29065 this.disabled = false;
29069 this.loaded = false;
29070 this.closable = closable;
29073 * The body element for this TabPanelItem.
29074 * @type Roo.Element
29076 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
29077 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
29078 this.bodyEl.setStyle("display", "block");
29079 this.bodyEl.setStyle("zoom", "1");
29082 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
29084 this.el = Roo.get(els.el, true);
29085 this.inner = Roo.get(els.inner, true);
29086 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
29087 this.pnode = Roo.get(els.el.parentNode, true);
29088 this.el.on("mousedown", this.onTabMouseDown, this);
29089 this.el.on("click", this.onTabClick, this);
29092 var c = Roo.get(els.close, true);
29093 c.dom.title = this.closeText;
29094 c.addClassOnOver("close-over");
29095 c.on("click", this.closeClick, this);
29101 * Fires when this tab becomes the active tab.
29102 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29103 * @param {Roo.TabPanelItem} this
29107 * @event beforeclose
29108 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
29109 * @param {Roo.TabPanelItem} this
29110 * @param {Object} e Set cancel to true on this object to cancel the close.
29112 "beforeclose": true,
29115 * Fires when this tab is closed.
29116 * @param {Roo.TabPanelItem} this
29120 * @event deactivate
29121 * Fires when this tab is no longer the active tab.
29122 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29123 * @param {Roo.TabPanelItem} this
29125 "deactivate" : true
29127 this.hidden = false;
29129 Roo.TabPanelItem.superclass.constructor.call(this);
29132 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
29133 purgeListeners : function(){
29134 Roo.util.Observable.prototype.purgeListeners.call(this);
29135 this.el.removeAllListeners();
29138 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
29141 this.pnode.addClass("on");
29144 this.tabPanel.stripWrap.repaint();
29146 this.fireEvent("activate", this.tabPanel, this);
29150 * Returns true if this tab is the active tab.
29151 * @return {Boolean}
29153 isActive : function(){
29154 return this.tabPanel.getActiveTab() == this;
29158 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29161 this.pnode.removeClass("on");
29163 this.fireEvent("deactivate", this.tabPanel, this);
29166 hideAction : function(){
29167 this.bodyEl.hide();
29168 this.bodyEl.setStyle("position", "absolute");
29169 this.bodyEl.setLeft("-20000px");
29170 this.bodyEl.setTop("-20000px");
29173 showAction : function(){
29174 this.bodyEl.setStyle("position", "relative");
29175 this.bodyEl.setTop("");
29176 this.bodyEl.setLeft("");
29177 this.bodyEl.show();
29181 * Set the tooltip for the tab.
29182 * @param {String} tooltip The tab's tooltip
29184 setTooltip : function(text){
29185 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29186 this.textEl.dom.qtip = text;
29187 this.textEl.dom.removeAttribute('title');
29189 this.textEl.dom.title = text;
29193 onTabClick : function(e){
29194 e.preventDefault();
29195 this.tabPanel.activate(this.id);
29198 onTabMouseDown : function(e){
29199 e.preventDefault();
29200 this.tabPanel.activate(this.id);
29203 getWidth : function(){
29204 return this.inner.getWidth();
29207 setWidth : function(width){
29208 var iwidth = width - this.pnode.getPadding("lr");
29209 this.inner.setWidth(iwidth);
29210 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29211 this.pnode.setWidth(width);
29215 * Show or hide the tab
29216 * @param {Boolean} hidden True to hide or false to show.
29218 setHidden : function(hidden){
29219 this.hidden = hidden;
29220 this.pnode.setStyle("display", hidden ? "none" : "");
29224 * Returns true if this tab is "hidden"
29225 * @return {Boolean}
29227 isHidden : function(){
29228 return this.hidden;
29232 * Returns the text for this tab
29235 getText : function(){
29239 autoSize : function(){
29240 //this.el.beginMeasure();
29241 this.textEl.setWidth(1);
29243 * #2804 [new] Tabs in Roojs
29244 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29246 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29247 //this.el.endMeasure();
29251 * Sets the text for the tab (Note: this also sets the tooltip text)
29252 * @param {String} text The tab's text and tooltip
29254 setText : function(text){
29256 this.textEl.update(text);
29257 this.setTooltip(text);
29258 if(!this.tabPanel.resizeTabs){
29263 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29265 activate : function(){
29266 this.tabPanel.activate(this.id);
29270 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29272 disable : function(){
29273 if(this.tabPanel.active != this){
29274 this.disabled = true;
29275 this.pnode.addClass("disabled");
29280 * Enables this TabPanelItem if it was previously disabled.
29282 enable : function(){
29283 this.disabled = false;
29284 this.pnode.removeClass("disabled");
29288 * Sets the content for this TabPanelItem.
29289 * @param {String} content The content
29290 * @param {Boolean} loadScripts true to look for and load scripts
29292 setContent : function(content, loadScripts){
29293 this.bodyEl.update(content, loadScripts);
29297 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29298 * @return {Roo.UpdateManager} The UpdateManager
29300 getUpdateManager : function(){
29301 return this.bodyEl.getUpdateManager();
29305 * Set a URL to be used to load the content for this TabPanelItem.
29306 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29307 * @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)
29308 * @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)
29309 * @return {Roo.UpdateManager} The UpdateManager
29311 setUrl : function(url, params, loadOnce){
29312 if(this.refreshDelegate){
29313 this.un('activate', this.refreshDelegate);
29315 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29316 this.on("activate", this.refreshDelegate);
29317 return this.bodyEl.getUpdateManager();
29321 _handleRefresh : function(url, params, loadOnce){
29322 if(!loadOnce || !this.loaded){
29323 var updater = this.bodyEl.getUpdateManager();
29324 updater.update(url, params, this._setLoaded.createDelegate(this));
29329 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29330 * Will fail silently if the setUrl method has not been called.
29331 * This does not activate the panel, just updates its content.
29333 refresh : function(){
29334 if(this.refreshDelegate){
29335 this.loaded = false;
29336 this.refreshDelegate();
29341 _setLoaded : function(){
29342 this.loaded = true;
29346 closeClick : function(e){
29349 this.fireEvent("beforeclose", this, o);
29350 if(o.cancel !== true){
29351 this.tabPanel.removeTab(this.id);
29355 * The text displayed in the tooltip for the close icon.
29358 closeText : "Close this tab"
29362 Roo.TabPanel.prototype.createStrip = function(container){
29363 var strip = document.createElement("div");
29364 strip.className = "x-tabs-wrap";
29365 container.appendChild(strip);
29369 Roo.TabPanel.prototype.createStripList = function(strip){
29370 // div wrapper for retard IE
29371 // returns the "tr" element.
29372 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29373 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29374 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29375 return strip.firstChild.firstChild.firstChild.firstChild;
29378 Roo.TabPanel.prototype.createBody = function(container){
29379 var body = document.createElement("div");
29380 Roo.id(body, "tab-body");
29381 Roo.fly(body).addClass("x-tabs-body");
29382 container.appendChild(body);
29386 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29387 var body = Roo.getDom(id);
29389 body = document.createElement("div");
29392 Roo.fly(body).addClass("x-tabs-item-body");
29393 bodyEl.insertBefore(body, bodyEl.firstChild);
29397 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29398 var td = document.createElement("td");
29399 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29400 //stripEl.appendChild(td);
29402 td.className = "x-tabs-closable";
29403 if(!this.closeTpl){
29404 this.closeTpl = new Roo.Template(
29405 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29406 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29407 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29410 var el = this.closeTpl.overwrite(td, {"text": text});
29411 var close = el.getElementsByTagName("div")[0];
29412 var inner = el.getElementsByTagName("em")[0];
29413 return {"el": el, "close": close, "inner": inner};
29416 this.tabTpl = new Roo.Template(
29417 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29418 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29421 var el = this.tabTpl.overwrite(td, {"text": text});
29422 var inner = el.getElementsByTagName("em")[0];
29423 return {"el": el, "inner": inner};
29427 * Ext JS Library 1.1.1
29428 * Copyright(c) 2006-2007, Ext JS, LLC.
29430 * Originally Released Under LGPL - original licence link has changed is not relivant.
29433 * <script type="text/javascript">
29437 * @class Roo.Button
29438 * @extends Roo.util.Observable
29439 * Simple Button class
29440 * @cfg {String} text The button text
29441 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29442 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29443 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29444 * @cfg {Object} scope The scope of the handler
29445 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29446 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29447 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29448 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29449 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29450 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29451 applies if enableToggle = true)
29452 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29453 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29454 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29456 * Create a new button
29457 * @param {Object} config The config object
29459 Roo.Button = function(renderTo, config)
29463 renderTo = config.renderTo || false;
29466 Roo.apply(this, config);
29470 * Fires when this button is clicked
29471 * @param {Button} this
29472 * @param {EventObject} e The click event
29477 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29478 * @param {Button} this
29479 * @param {Boolean} pressed
29484 * Fires when the mouse hovers over the button
29485 * @param {Button} this
29486 * @param {Event} e The event object
29488 'mouseover' : true,
29491 * Fires when the mouse exits the button
29492 * @param {Button} this
29493 * @param {Event} e The event object
29498 * Fires when the button is rendered
29499 * @param {Button} this
29504 this.menu = Roo.menu.MenuMgr.get(this.menu);
29506 // register listeners first!! - so render can be captured..
29507 Roo.util.Observable.call(this);
29509 this.render(renderTo);
29515 Roo.extend(Roo.Button, Roo.util.Observable, {
29521 * Read-only. True if this button is hidden
29526 * Read-only. True if this button is disabled
29531 * Read-only. True if this button is pressed (only if enableToggle = true)
29537 * @cfg {Number} tabIndex
29538 * The DOM tabIndex for this button (defaults to undefined)
29540 tabIndex : undefined,
29543 * @cfg {Boolean} enableToggle
29544 * True to enable pressed/not pressed toggling (defaults to false)
29546 enableToggle: false,
29548 * @cfg {Roo.menu.Menu} menu
29549 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29553 * @cfg {String} menuAlign
29554 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29556 menuAlign : "tl-bl?",
29559 * @cfg {String} iconCls
29560 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29562 iconCls : undefined,
29564 * @cfg {String} type
29565 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29570 menuClassTarget: 'tr',
29573 * @cfg {String} clickEvent
29574 * The type of event to map to the button's event handler (defaults to 'click')
29576 clickEvent : 'click',
29579 * @cfg {Boolean} handleMouseEvents
29580 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29582 handleMouseEvents : true,
29585 * @cfg {String} tooltipType
29586 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29588 tooltipType : 'qtip',
29591 * @cfg {String} cls
29592 * A CSS class to apply to the button's main element.
29596 * @cfg {Roo.Template} template (Optional)
29597 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29598 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29599 * require code modifications if required elements (e.g. a button) aren't present.
29603 render : function(renderTo){
29605 if(this.hideParent){
29606 this.parentEl = Roo.get(renderTo);
29608 if(!this.dhconfig){
29609 if(!this.template){
29610 if(!Roo.Button.buttonTemplate){
29611 // hideous table template
29612 Roo.Button.buttonTemplate = new Roo.Template(
29613 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29614 '<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>',
29615 "</tr></tbody></table>");
29617 this.template = Roo.Button.buttonTemplate;
29619 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29620 var btnEl = btn.child("button:first");
29621 btnEl.on('focus', this.onFocus, this);
29622 btnEl.on('blur', this.onBlur, this);
29624 btn.addClass(this.cls);
29627 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29630 btnEl.addClass(this.iconCls);
29632 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29635 if(this.tabIndex !== undefined){
29636 btnEl.dom.tabIndex = this.tabIndex;
29639 if(typeof this.tooltip == 'object'){
29640 Roo.QuickTips.tips(Roo.apply({
29644 btnEl.dom[this.tooltipType] = this.tooltip;
29648 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29652 this.el.dom.id = this.el.id = this.id;
29655 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29656 this.menu.on("show", this.onMenuShow, this);
29657 this.menu.on("hide", this.onMenuHide, this);
29659 btn.addClass("x-btn");
29660 if(Roo.isIE && !Roo.isIE7){
29661 this.autoWidth.defer(1, this);
29665 if(this.handleMouseEvents){
29666 btn.on("mouseover", this.onMouseOver, this);
29667 btn.on("mouseout", this.onMouseOut, this);
29668 btn.on("mousedown", this.onMouseDown, this);
29670 btn.on(this.clickEvent, this.onClick, this);
29671 //btn.on("mouseup", this.onMouseUp, this);
29678 Roo.ButtonToggleMgr.register(this);
29680 this.el.addClass("x-btn-pressed");
29683 var repeater = new Roo.util.ClickRepeater(btn,
29684 typeof this.repeat == "object" ? this.repeat : {}
29686 repeater.on("click", this.onClick, this);
29689 this.fireEvent('render', this);
29693 * Returns the button's underlying element
29694 * @return {Roo.Element} The element
29696 getEl : function(){
29701 * Destroys this Button and removes any listeners.
29703 destroy : function(){
29704 Roo.ButtonToggleMgr.unregister(this);
29705 this.el.removeAllListeners();
29706 this.purgeListeners();
29711 autoWidth : function(){
29713 this.el.setWidth("auto");
29714 if(Roo.isIE7 && Roo.isStrict){
29715 var ib = this.el.child('button');
29716 if(ib && ib.getWidth() > 20){
29718 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29723 this.el.beginMeasure();
29725 if(this.el.getWidth() < this.minWidth){
29726 this.el.setWidth(this.minWidth);
29729 this.el.endMeasure();
29736 * Assigns this button's click handler
29737 * @param {Function} handler The function to call when the button is clicked
29738 * @param {Object} scope (optional) Scope for the function passed in
29740 setHandler : function(handler, scope){
29741 this.handler = handler;
29742 this.scope = scope;
29746 * Sets this button's text
29747 * @param {String} text The button text
29749 setText : function(text){
29752 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29758 * Gets the text for this button
29759 * @return {String} The button text
29761 getText : function(){
29769 this.hidden = false;
29771 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29779 this.hidden = true;
29781 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29786 * Convenience function for boolean show/hide
29787 * @param {Boolean} visible True to show, false to hide
29789 setVisible: function(visible){
29798 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29799 * @param {Boolean} state (optional) Force a particular state
29801 toggle : function(state){
29802 state = state === undefined ? !this.pressed : state;
29803 if(state != this.pressed){
29805 this.el.addClass("x-btn-pressed");
29806 this.pressed = true;
29807 this.fireEvent("toggle", this, true);
29809 this.el.removeClass("x-btn-pressed");
29810 this.pressed = false;
29811 this.fireEvent("toggle", this, false);
29813 if(this.toggleHandler){
29814 this.toggleHandler.call(this.scope || this, this, state);
29822 focus : function(){
29823 this.el.child('button:first').focus();
29827 * Disable this button
29829 disable : function(){
29831 this.el.addClass("x-btn-disabled");
29833 this.disabled = true;
29837 * Enable this button
29839 enable : function(){
29841 this.el.removeClass("x-btn-disabled");
29843 this.disabled = false;
29847 * Convenience function for boolean enable/disable
29848 * @param {Boolean} enabled True to enable, false to disable
29850 setDisabled : function(v){
29851 this[v !== true ? "enable" : "disable"]();
29855 onClick : function(e)
29858 e.preventDefault();
29863 if(!this.disabled){
29864 if(this.enableToggle){
29867 if(this.menu && !this.menu.isVisible()){
29868 this.menu.show(this.el, this.menuAlign);
29870 this.fireEvent("click", this, e);
29872 this.el.removeClass("x-btn-over");
29873 this.handler.call(this.scope || this, this, e);
29878 onMouseOver : function(e){
29879 if(!this.disabled){
29880 this.el.addClass("x-btn-over");
29881 this.fireEvent('mouseover', this, e);
29885 onMouseOut : function(e){
29886 if(!e.within(this.el, true)){
29887 this.el.removeClass("x-btn-over");
29888 this.fireEvent('mouseout', this, e);
29892 onFocus : function(e){
29893 if(!this.disabled){
29894 this.el.addClass("x-btn-focus");
29898 onBlur : function(e){
29899 this.el.removeClass("x-btn-focus");
29902 onMouseDown : function(e){
29903 if(!this.disabled && e.button == 0){
29904 this.el.addClass("x-btn-click");
29905 Roo.get(document).on('mouseup', this.onMouseUp, this);
29909 onMouseUp : function(e){
29911 this.el.removeClass("x-btn-click");
29912 Roo.get(document).un('mouseup', this.onMouseUp, this);
29916 onMenuShow : function(e){
29917 this.el.addClass("x-btn-menu-active");
29920 onMenuHide : function(e){
29921 this.el.removeClass("x-btn-menu-active");
29925 // Private utility class used by Button
29926 Roo.ButtonToggleMgr = function(){
29929 function toggleGroup(btn, state){
29931 var g = groups[btn.toggleGroup];
29932 for(var i = 0, l = g.length; i < l; i++){
29934 g[i].toggle(false);
29941 register : function(btn){
29942 if(!btn.toggleGroup){
29945 var g = groups[btn.toggleGroup];
29947 g = groups[btn.toggleGroup] = [];
29950 btn.on("toggle", toggleGroup);
29953 unregister : function(btn){
29954 if(!btn.toggleGroup){
29957 var g = groups[btn.toggleGroup];
29960 btn.un("toggle", toggleGroup);
29966 * Ext JS Library 1.1.1
29967 * Copyright(c) 2006-2007, Ext JS, LLC.
29969 * Originally Released Under LGPL - original licence link has changed is not relivant.
29972 * <script type="text/javascript">
29976 * @class Roo.SplitButton
29977 * @extends Roo.Button
29978 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29979 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29980 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29981 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29982 * @cfg {String} arrowTooltip The title attribute of the arrow
29984 * Create a new menu button
29985 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29986 * @param {Object} config The config object
29988 Roo.SplitButton = function(renderTo, config){
29989 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29991 * @event arrowclick
29992 * Fires when this button's arrow is clicked
29993 * @param {SplitButton} this
29994 * @param {EventObject} e The click event
29996 this.addEvents({"arrowclick":true});
29999 Roo.extend(Roo.SplitButton, Roo.Button, {
30000 render : function(renderTo){
30001 // this is one sweet looking template!
30002 var tpl = new Roo.Template(
30003 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
30004 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
30005 '<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>',
30006 "</tbody></table></td><td>",
30007 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
30008 '<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>',
30009 "</tbody></table></td></tr></table>"
30011 var btn = tpl.append(renderTo, [this.text, this.type], true);
30012 var btnEl = btn.child("button");
30014 btn.addClass(this.cls);
30017 btnEl.setStyle('background-image', 'url(' +this.icon +')');
30020 btnEl.addClass(this.iconCls);
30022 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
30026 if(this.handleMouseEvents){
30027 btn.on("mouseover", this.onMouseOver, this);
30028 btn.on("mouseout", this.onMouseOut, this);
30029 btn.on("mousedown", this.onMouseDown, this);
30030 btn.on("mouseup", this.onMouseUp, this);
30032 btn.on(this.clickEvent, this.onClick, this);
30034 if(typeof this.tooltip == 'object'){
30035 Roo.QuickTips.tips(Roo.apply({
30039 btnEl.dom[this.tooltipType] = this.tooltip;
30042 if(this.arrowTooltip){
30043 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
30052 this.el.addClass("x-btn-pressed");
30054 if(Roo.isIE && !Roo.isIE7){
30055 this.autoWidth.defer(1, this);
30060 this.menu.on("show", this.onMenuShow, this);
30061 this.menu.on("hide", this.onMenuHide, this);
30063 this.fireEvent('render', this);
30067 autoWidth : function(){
30069 var tbl = this.el.child("table:first");
30070 var tbl2 = this.el.child("table:last");
30071 this.el.setWidth("auto");
30072 tbl.setWidth("auto");
30073 if(Roo.isIE7 && Roo.isStrict){
30074 var ib = this.el.child('button:first');
30075 if(ib && ib.getWidth() > 20){
30077 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30082 this.el.beginMeasure();
30084 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
30085 tbl.setWidth(this.minWidth-tbl2.getWidth());
30088 this.el.endMeasure();
30091 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
30095 * Sets this button's click handler
30096 * @param {Function} handler The function to call when the button is clicked
30097 * @param {Object} scope (optional) Scope for the function passed above
30099 setHandler : function(handler, scope){
30100 this.handler = handler;
30101 this.scope = scope;
30105 * Sets this button's arrow click handler
30106 * @param {Function} handler The function to call when the arrow is clicked
30107 * @param {Object} scope (optional) Scope for the function passed above
30109 setArrowHandler : function(handler, scope){
30110 this.arrowHandler = handler;
30111 this.scope = scope;
30117 focus : function(){
30119 this.el.child("button:first").focus();
30124 onClick : function(e){
30125 e.preventDefault();
30126 if(!this.disabled){
30127 if(e.getTarget(".x-btn-menu-arrow-wrap")){
30128 if(this.menu && !this.menu.isVisible()){
30129 this.menu.show(this.el, this.menuAlign);
30131 this.fireEvent("arrowclick", this, e);
30132 if(this.arrowHandler){
30133 this.arrowHandler.call(this.scope || this, this, e);
30136 this.fireEvent("click", this, e);
30138 this.handler.call(this.scope || this, this, e);
30144 onMouseDown : function(e){
30145 if(!this.disabled){
30146 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30150 onMouseUp : function(e){
30151 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30156 // backwards compat
30157 Roo.MenuButton = Roo.SplitButton;/*
30159 * Ext JS Library 1.1.1
30160 * Copyright(c) 2006-2007, Ext JS, LLC.
30162 * Originally Released Under LGPL - original licence link has changed is not relivant.
30165 * <script type="text/javascript">
30169 * @class Roo.Toolbar
30170 * @children Roo.Toolbar.Item Roo.form.Field
30171 * Basic Toolbar class.
30173 * Creates a new Toolbar
30174 * @param {Object} container The config object
30176 Roo.Toolbar = function(container, buttons, config)
30178 /// old consturctor format still supported..
30179 if(container instanceof Array){ // omit the container for later rendering
30180 buttons = container;
30184 if (typeof(container) == 'object' && container.xtype) {
30185 config = container;
30186 container = config.container;
30187 buttons = config.buttons || []; // not really - use items!!
30190 if (config && config.items) {
30191 xitems = config.items;
30192 delete config.items;
30194 Roo.apply(this, config);
30195 this.buttons = buttons;
30198 this.render(container);
30200 this.xitems = xitems;
30201 Roo.each(xitems, function(b) {
30207 Roo.Toolbar.prototype = {
30209 * @cfg {Array} items
30210 * array of button configs or elements to add (will be converted to a MixedCollection)
30214 * @cfg {String/HTMLElement/Element} container
30215 * The id or element that will contain the toolbar
30218 render : function(ct){
30219 this.el = Roo.get(ct);
30221 this.el.addClass(this.cls);
30223 // using a table allows for vertical alignment
30224 // 100% width is needed by Safari...
30225 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30226 this.tr = this.el.child("tr", true);
30228 this.items = new Roo.util.MixedCollection(false, function(o){
30229 return o.id || ("item" + (++autoId));
30232 this.add.apply(this, this.buttons);
30233 delete this.buttons;
30238 * Adds element(s) to the toolbar -- this function takes a variable number of
30239 * arguments of mixed type and adds them to the toolbar.
30240 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30242 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30243 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30244 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30245 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30246 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30247 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30248 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30249 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30250 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30252 * @param {Mixed} arg2
30253 * @param {Mixed} etc.
30256 var a = arguments, l = a.length;
30257 for(var i = 0; i < l; i++){
30262 _add : function(el) {
30265 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30268 if (el.applyTo){ // some kind of form field
30269 return this.addField(el);
30271 if (el.render){ // some kind of Toolbar.Item
30272 return this.addItem(el);
30274 if (typeof el == "string"){ // string
30275 if(el == "separator" || el == "-"){
30276 return this.addSeparator();
30279 return this.addSpacer();
30282 return this.addFill();
30284 return this.addText(el);
30287 if(el.tagName){ // element
30288 return this.addElement(el);
30290 if(typeof el == "object"){ // must be button config?
30291 return this.addButton(el);
30293 // and now what?!?!
30299 * Add an Xtype element
30300 * @param {Object} xtype Xtype Object
30301 * @return {Object} created Object
30303 addxtype : function(e){
30304 return this.add(e);
30308 * Returns the Element for this toolbar.
30309 * @return {Roo.Element}
30311 getEl : function(){
30317 * @return {Roo.Toolbar.Item} The separator item
30319 addSeparator : function(){
30320 return this.addItem(new Roo.Toolbar.Separator());
30324 * Adds a spacer element
30325 * @return {Roo.Toolbar.Spacer} The spacer item
30327 addSpacer : function(){
30328 return this.addItem(new Roo.Toolbar.Spacer());
30332 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30333 * @return {Roo.Toolbar.Fill} The fill item
30335 addFill : function(){
30336 return this.addItem(new Roo.Toolbar.Fill());
30340 * Adds any standard HTML element to the toolbar
30341 * @param {String/HTMLElement/Element} el The element or id of the element to add
30342 * @return {Roo.Toolbar.Item} The element's item
30344 addElement : function(el){
30345 return this.addItem(new Roo.Toolbar.Item(el));
30348 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30349 * @type Roo.util.MixedCollection
30354 * Adds any Toolbar.Item or subclass
30355 * @param {Roo.Toolbar.Item} item
30356 * @return {Roo.Toolbar.Item} The item
30358 addItem : function(item){
30359 var td = this.nextBlock();
30361 this.items.add(item);
30366 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30367 * @param {Object/Array} config A button config or array of configs
30368 * @return {Roo.Toolbar.Button/Array}
30370 addButton : function(config){
30371 if(config instanceof Array){
30373 for(var i = 0, len = config.length; i < len; i++) {
30374 buttons.push(this.addButton(config[i]));
30379 if(!(config instanceof Roo.Toolbar.Button)){
30381 new Roo.Toolbar.SplitButton(config) :
30382 new Roo.Toolbar.Button(config);
30384 var td = this.nextBlock();
30391 * Adds text to the toolbar
30392 * @param {String} text The text to add
30393 * @return {Roo.Toolbar.Item} The element's item
30395 addText : function(text){
30396 return this.addItem(new Roo.Toolbar.TextItem(text));
30400 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30401 * @param {Number} index The index where the item is to be inserted
30402 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30403 * @return {Roo.Toolbar.Button/Item}
30405 insertButton : function(index, item){
30406 if(item instanceof Array){
30408 for(var i = 0, len = item.length; i < len; i++) {
30409 buttons.push(this.insertButton(index + i, item[i]));
30413 if (!(item instanceof Roo.Toolbar.Button)){
30414 item = new Roo.Toolbar.Button(item);
30416 var td = document.createElement("td");
30417 this.tr.insertBefore(td, this.tr.childNodes[index]);
30419 this.items.insert(index, item);
30424 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30425 * @param {Object} config
30426 * @return {Roo.Toolbar.Item} The element's item
30428 addDom : function(config, returnEl){
30429 var td = this.nextBlock();
30430 Roo.DomHelper.overwrite(td, config);
30431 var ti = new Roo.Toolbar.Item(td.firstChild);
30433 this.items.add(ti);
30438 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30439 * @type Roo.util.MixedCollection
30444 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30445 * Note: the field should not have been rendered yet. For a field that has already been
30446 * rendered, use {@link #addElement}.
30447 * @param {Roo.form.Field} field
30448 * @return {Roo.ToolbarItem}
30452 addField : function(field) {
30453 if (!this.fields) {
30455 this.fields = new Roo.util.MixedCollection(false, function(o){
30456 return o.id || ("item" + (++autoId));
30461 var td = this.nextBlock();
30463 var ti = new Roo.Toolbar.Item(td.firstChild);
30465 this.items.add(ti);
30466 this.fields.add(field);
30477 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30478 this.el.child('div').hide();
30486 this.el.child('div').show();
30490 nextBlock : function(){
30491 var td = document.createElement("td");
30492 this.tr.appendChild(td);
30497 destroy : function(){
30498 if(this.items){ // rendered?
30499 Roo.destroy.apply(Roo, this.items.items);
30501 if(this.fields){ // rendered?
30502 Roo.destroy.apply(Roo, this.fields.items);
30504 Roo.Element.uncache(this.el, this.tr);
30509 * @class Roo.Toolbar.Item
30510 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30512 * Creates a new Item
30513 * @param {HTMLElement} el
30515 Roo.Toolbar.Item = function(el){
30517 if (typeof (el.xtype) != 'undefined') {
30522 this.el = Roo.getDom(el);
30523 this.id = Roo.id(this.el);
30524 this.hidden = false;
30529 * Fires when the button is rendered
30530 * @param {Button} this
30534 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30536 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30537 //Roo.Toolbar.Item.prototype = {
30540 * Get this item's HTML Element
30541 * @return {HTMLElement}
30543 getEl : function(){
30548 render : function(td){
30551 td.appendChild(this.el);
30553 this.fireEvent('render', this);
30557 * Removes and destroys this item.
30559 destroy : function(){
30560 this.td.parentNode.removeChild(this.td);
30567 this.hidden = false;
30568 this.td.style.display = "";
30575 this.hidden = true;
30576 this.td.style.display = "none";
30580 * Convenience function for boolean show/hide.
30581 * @param {Boolean} visible true to show/false to hide
30583 setVisible: function(visible){
30592 * Try to focus this item.
30594 focus : function(){
30595 Roo.fly(this.el).focus();
30599 * Disables this item.
30601 disable : function(){
30602 Roo.fly(this.td).addClass("x-item-disabled");
30603 this.disabled = true;
30604 this.el.disabled = true;
30608 * Enables this item.
30610 enable : function(){
30611 Roo.fly(this.td).removeClass("x-item-disabled");
30612 this.disabled = false;
30613 this.el.disabled = false;
30619 * @class Roo.Toolbar.Separator
30620 * @extends Roo.Toolbar.Item
30621 * A simple toolbar separator class
30623 * Creates a new Separator
30625 Roo.Toolbar.Separator = function(cfg){
30627 var s = document.createElement("span");
30628 s.className = "ytb-sep";
30633 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30635 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30636 enable:Roo.emptyFn,
30637 disable:Roo.emptyFn,
30642 * @class Roo.Toolbar.Spacer
30643 * @extends Roo.Toolbar.Item
30644 * A simple element that adds extra horizontal space to a toolbar.
30646 * Creates a new Spacer
30648 Roo.Toolbar.Spacer = function(cfg){
30649 var s = document.createElement("div");
30650 s.className = "ytb-spacer";
30654 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30656 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30657 enable:Roo.emptyFn,
30658 disable:Roo.emptyFn,
30663 * @class Roo.Toolbar.Fill
30664 * @extends Roo.Toolbar.Spacer
30665 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30667 * Creates a new Spacer
30669 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30671 render : function(td){
30672 td.style.width = '100%';
30673 Roo.Toolbar.Fill.superclass.render.call(this, td);
30678 * @class Roo.Toolbar.TextItem
30679 * @extends Roo.Toolbar.Item
30680 * A simple class that renders text directly into a toolbar.
30682 * Creates a new TextItem
30683 * @cfg {string} text
30685 Roo.Toolbar.TextItem = function(cfg){
30686 var text = cfg || "";
30687 if (typeof(cfg) == 'object') {
30688 text = cfg.text || "";
30692 var s = document.createElement("span");
30693 s.className = "ytb-text";
30694 s.innerHTML = text;
30699 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30701 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30704 enable:Roo.emptyFn,
30705 disable:Roo.emptyFn,
30710 * @class Roo.Toolbar.Button
30711 * @extends Roo.Button
30712 * A button that renders into a toolbar.
30714 * Creates a new Button
30715 * @param {Object} config A standard {@link Roo.Button} config object
30717 Roo.Toolbar.Button = function(config){
30718 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30720 Roo.extend(Roo.Toolbar.Button, Roo.Button,
30724 render : function(td){
30726 Roo.Toolbar.Button.superclass.render.call(this, td);
30730 * Removes and destroys this button
30732 destroy : function(){
30733 Roo.Toolbar.Button.superclass.destroy.call(this);
30734 this.td.parentNode.removeChild(this.td);
30738 * Shows this button
30741 this.hidden = false;
30742 this.td.style.display = "";
30746 * Hides this button
30749 this.hidden = true;
30750 this.td.style.display = "none";
30754 * Disables this item
30756 disable : function(){
30757 Roo.fly(this.td).addClass("x-item-disabled");
30758 this.disabled = true;
30762 * Enables this item
30764 enable : function(){
30765 Roo.fly(this.td).removeClass("x-item-disabled");
30766 this.disabled = false;
30769 // backwards compat
30770 Roo.ToolbarButton = Roo.Toolbar.Button;
30773 * @class Roo.Toolbar.SplitButton
30774 * @extends Roo.SplitButton
30775 * A menu button that renders into a toolbar.
30777 * Creates a new SplitButton
30778 * @param {Object} config A standard {@link Roo.SplitButton} config object
30780 Roo.Toolbar.SplitButton = function(config){
30781 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30783 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30784 render : function(td){
30786 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30790 * Removes and destroys this button
30792 destroy : function(){
30793 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30794 this.td.parentNode.removeChild(this.td);
30798 * Shows this button
30801 this.hidden = false;
30802 this.td.style.display = "";
30806 * Hides this button
30809 this.hidden = true;
30810 this.td.style.display = "none";
30814 // backwards compat
30815 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30817 * Ext JS Library 1.1.1
30818 * Copyright(c) 2006-2007, Ext JS, LLC.
30820 * Originally Released Under LGPL - original licence link has changed is not relivant.
30823 * <script type="text/javascript">
30827 * @class Roo.PagingToolbar
30828 * @extends Roo.Toolbar
30829 * @children Roo.Toolbar.Item Roo.form.Field
30830 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30832 * Create a new PagingToolbar
30833 * @param {Object} config The config object
30835 Roo.PagingToolbar = function(el, ds, config)
30837 // old args format still supported... - xtype is prefered..
30838 if (typeof(el) == 'object' && el.xtype) {
30839 // created from xtype...
30841 ds = el.dataSource;
30842 el = config.container;
30845 if (config.items) {
30846 items = config.items;
30850 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30853 this.renderButtons(this.el);
30856 // supprot items array.
30858 Roo.each(items, function(e) {
30859 this.add(Roo.factory(e));
30864 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30867 * @cfg {String/HTMLElement/Element} container
30868 * container The id or element that will contain the toolbar
30871 * @cfg {Boolean} displayInfo
30872 * True to display the displayMsg (defaults to false)
30877 * @cfg {Number} pageSize
30878 * The number of records to display per page (defaults to 20)
30882 * @cfg {String} displayMsg
30883 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30885 displayMsg : 'Displaying {0} - {1} of {2}',
30887 * @cfg {String} emptyMsg
30888 * The message to display when no records are found (defaults to "No data to display")
30890 emptyMsg : 'No data to display',
30892 * Customizable piece of the default paging text (defaults to "Page")
30895 beforePageText : "Page",
30897 * Customizable piece of the default paging text (defaults to "of %0")
30900 afterPageText : "of {0}",
30902 * Customizable piece of the default paging text (defaults to "First Page")
30905 firstText : "First Page",
30907 * Customizable piece of the default paging text (defaults to "Previous Page")
30910 prevText : "Previous Page",
30912 * Customizable piece of the default paging text (defaults to "Next Page")
30915 nextText : "Next Page",
30917 * Customizable piece of the default paging text (defaults to "Last Page")
30920 lastText : "Last Page",
30922 * Customizable piece of the default paging text (defaults to "Refresh")
30925 refreshText : "Refresh",
30928 renderButtons : function(el){
30929 Roo.PagingToolbar.superclass.render.call(this, el);
30930 this.first = this.addButton({
30931 tooltip: this.firstText,
30932 cls: "x-btn-icon x-grid-page-first",
30934 handler: this.onClick.createDelegate(this, ["first"])
30936 this.prev = this.addButton({
30937 tooltip: this.prevText,
30938 cls: "x-btn-icon x-grid-page-prev",
30940 handler: this.onClick.createDelegate(this, ["prev"])
30942 //this.addSeparator();
30943 this.add(this.beforePageText);
30944 this.field = Roo.get(this.addDom({
30949 cls: "x-grid-page-number"
30951 this.field.on("keydown", this.onPagingKeydown, this);
30952 this.field.on("focus", function(){this.dom.select();});
30953 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30954 this.field.setHeight(18);
30955 //this.addSeparator();
30956 this.next = this.addButton({
30957 tooltip: this.nextText,
30958 cls: "x-btn-icon x-grid-page-next",
30960 handler: this.onClick.createDelegate(this, ["next"])
30962 this.last = this.addButton({
30963 tooltip: this.lastText,
30964 cls: "x-btn-icon x-grid-page-last",
30966 handler: this.onClick.createDelegate(this, ["last"])
30968 //this.addSeparator();
30969 this.loading = this.addButton({
30970 tooltip: this.refreshText,
30971 cls: "x-btn-icon x-grid-loading",
30972 handler: this.onClick.createDelegate(this, ["refresh"])
30975 if(this.displayInfo){
30976 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30981 updateInfo : function(){
30982 if(this.displayEl){
30983 var count = this.ds.getCount();
30984 var msg = count == 0 ?
30988 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30990 this.displayEl.update(msg);
30995 onLoad : function(ds, r, o){
30996 this.cursor = o.params ? o.params.start : 0;
30997 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30999 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
31000 this.field.dom.value = ap;
31001 this.first.setDisabled(ap == 1);
31002 this.prev.setDisabled(ap == 1);
31003 this.next.setDisabled(ap == ps);
31004 this.last.setDisabled(ap == ps);
31005 this.loading.enable();
31010 getPageData : function(){
31011 var total = this.ds.getTotalCount();
31014 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
31015 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
31020 onLoadError : function(){
31021 this.loading.enable();
31025 onPagingKeydown : function(e){
31026 var k = e.getKey();
31027 var d = this.getPageData();
31029 var v = this.field.dom.value, pageNum;
31030 if(!v || isNaN(pageNum = parseInt(v, 10))){
31031 this.field.dom.value = d.activePage;
31034 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
31035 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31038 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))
31040 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
31041 this.field.dom.value = pageNum;
31042 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
31045 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
31047 var v = this.field.dom.value, pageNum;
31048 var increment = (e.shiftKey) ? 10 : 1;
31049 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
31052 if(!v || isNaN(pageNum = parseInt(v, 10))) {
31053 this.field.dom.value = d.activePage;
31056 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
31058 this.field.dom.value = parseInt(v, 10) + increment;
31059 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
31060 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31067 beforeLoad : function(){
31069 this.loading.disable();
31074 onClick : function(which){
31078 ds.load({params:{start: 0, limit: this.pageSize}});
31081 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
31084 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
31087 var total = ds.getTotalCount();
31088 var extra = total % this.pageSize;
31089 var lastStart = extra ? (total - extra) : total-this.pageSize;
31090 ds.load({params:{start: lastStart, limit: this.pageSize}});
31093 ds.load({params:{start: this.cursor, limit: this.pageSize}});
31099 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
31100 * @param {Roo.data.Store} store The data store to unbind
31102 unbind : function(ds){
31103 ds.un("beforeload", this.beforeLoad, this);
31104 ds.un("load", this.onLoad, this);
31105 ds.un("loadexception", this.onLoadError, this);
31106 ds.un("remove", this.updateInfo, this);
31107 ds.un("add", this.updateInfo, this);
31108 this.ds = undefined;
31112 * Binds the paging toolbar to the specified {@link Roo.data.Store}
31113 * @param {Roo.data.Store} store The data store to bind
31115 bind : function(ds){
31116 ds.on("beforeload", this.beforeLoad, this);
31117 ds.on("load", this.onLoad, this);
31118 ds.on("loadexception", this.onLoadError, this);
31119 ds.on("remove", this.updateInfo, this);
31120 ds.on("add", this.updateInfo, this);
31125 * Ext JS Library 1.1.1
31126 * Copyright(c) 2006-2007, Ext JS, LLC.
31128 * Originally Released Under LGPL - original licence link has changed is not relivant.
31131 * <script type="text/javascript">
31135 * @class Roo.Resizable
31136 * @extends Roo.util.Observable
31137 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
31138 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
31139 * 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
31140 * the element will be wrapped for you automatically.</p>
31141 * <p>Here is the list of valid resize handles:</p>
31144 ------ -------------------
31153 'hd' horizontal drag
31156 * <p>Here's an example showing the creation of a typical Resizable:</p>
31158 var resizer = new Roo.Resizable("element-id", {
31166 resizer.on("resize", myHandler);
31168 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31169 * resizer.east.setDisplayed(false);</p>
31170 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31171 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31172 * resize operation's new size (defaults to [0, 0])
31173 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31174 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31175 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31176 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31177 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31178 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31179 * @cfg {Number} width The width of the element in pixels (defaults to null)
31180 * @cfg {Number} height The height of the element in pixels (defaults to null)
31181 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31182 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31183 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31184 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31185 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31186 * in favor of the handles config option (defaults to false)
31187 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31188 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31189 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31190 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31191 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31192 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31193 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31194 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31195 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31196 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31197 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31199 * Create a new resizable component
31200 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31201 * @param {Object} config configuration options
31203 Roo.Resizable = function(el, config)
31205 this.el = Roo.get(el);
31207 if(config && config.wrap){
31208 config.resizeChild = this.el;
31209 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31210 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31211 this.el.setStyle("overflow", "hidden");
31212 this.el.setPositioning(config.resizeChild.getPositioning());
31213 config.resizeChild.clearPositioning();
31214 if(!config.width || !config.height){
31215 var csize = config.resizeChild.getSize();
31216 this.el.setSize(csize.width, csize.height);
31218 if(config.pinned && !config.adjustments){
31219 config.adjustments = "auto";
31223 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31224 this.proxy.unselectable();
31225 this.proxy.enableDisplayMode('block');
31227 Roo.apply(this, config);
31230 this.disableTrackOver = true;
31231 this.el.addClass("x-resizable-pinned");
31233 // if the element isn't positioned, make it relative
31234 var position = this.el.getStyle("position");
31235 if(position != "absolute" && position != "fixed"){
31236 this.el.setStyle("position", "relative");
31238 if(!this.handles){ // no handles passed, must be legacy style
31239 this.handles = 's,e,se';
31240 if(this.multiDirectional){
31241 this.handles += ',n,w';
31244 if(this.handles == "all"){
31245 this.handles = "n s e w ne nw se sw";
31247 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31248 var ps = Roo.Resizable.positions;
31249 for(var i = 0, len = hs.length; i < len; i++){
31250 if(hs[i] && ps[hs[i]]){
31251 var pos = ps[hs[i]];
31252 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31256 this.corner = this.southeast;
31258 // updateBox = the box can move..
31259 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31260 this.updateBox = true;
31263 this.activeHandle = null;
31265 if(this.resizeChild){
31266 if(typeof this.resizeChild == "boolean"){
31267 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31269 this.resizeChild = Roo.get(this.resizeChild, true);
31273 if(this.adjustments == "auto"){
31274 var rc = this.resizeChild;
31275 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31276 if(rc && (hw || hn)){
31277 rc.position("relative");
31278 rc.setLeft(hw ? hw.el.getWidth() : 0);
31279 rc.setTop(hn ? hn.el.getHeight() : 0);
31281 this.adjustments = [
31282 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31283 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31287 if(this.draggable){
31288 this.dd = this.dynamic ?
31289 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31290 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31296 * @event beforeresize
31297 * Fired before resize is allowed. Set enabled to false to cancel resize.
31298 * @param {Roo.Resizable} this
31299 * @param {Roo.EventObject} e The mousedown event
31301 "beforeresize" : true,
31304 * Fired a resizing.
31305 * @param {Roo.Resizable} this
31306 * @param {Number} x The new x position
31307 * @param {Number} y The new y position
31308 * @param {Number} w The new w width
31309 * @param {Number} h The new h hight
31310 * @param {Roo.EventObject} e The mouseup event
31315 * Fired after a resize.
31316 * @param {Roo.Resizable} this
31317 * @param {Number} width The new width
31318 * @param {Number} height The new height
31319 * @param {Roo.EventObject} e The mouseup event
31324 if(this.width !== null && this.height !== null){
31325 this.resizeTo(this.width, this.height);
31327 this.updateChildSize();
31330 this.el.dom.style.zoom = 1;
31332 Roo.Resizable.superclass.constructor.call(this);
31335 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31336 resizeChild : false,
31337 adjustments : [0, 0],
31347 multiDirectional : false,
31348 disableTrackOver : false,
31349 easing : 'easeOutStrong',
31350 widthIncrement : 0,
31351 heightIncrement : 0,
31355 preserveRatio : false,
31356 transparent: false,
31362 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31364 constrainTo: undefined,
31366 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31368 resizeRegion: undefined,
31372 * Perform a manual resize
31373 * @param {Number} width
31374 * @param {Number} height
31376 resizeTo : function(width, height){
31377 this.el.setSize(width, height);
31378 this.updateChildSize();
31379 this.fireEvent("resize", this, width, height, null);
31383 startSizing : function(e, handle){
31384 this.fireEvent("beforeresize", this, e);
31385 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31388 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31389 this.overlay.unselectable();
31390 this.overlay.enableDisplayMode("block");
31391 this.overlay.on("mousemove", this.onMouseMove, this);
31392 this.overlay.on("mouseup", this.onMouseUp, this);
31394 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31396 this.resizing = true;
31397 this.startBox = this.el.getBox();
31398 this.startPoint = e.getXY();
31399 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31400 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31402 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31403 this.overlay.show();
31405 if(this.constrainTo) {
31406 var ct = Roo.get(this.constrainTo);
31407 this.resizeRegion = ct.getRegion().adjust(
31408 ct.getFrameWidth('t'),
31409 ct.getFrameWidth('l'),
31410 -ct.getFrameWidth('b'),
31411 -ct.getFrameWidth('r')
31415 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31417 this.proxy.setBox(this.startBox);
31419 this.proxy.setStyle('visibility', 'visible');
31425 onMouseDown : function(handle, e){
31428 this.activeHandle = handle;
31429 this.startSizing(e, handle);
31434 onMouseUp : function(e){
31435 var size = this.resizeElement();
31436 this.resizing = false;
31438 this.overlay.hide();
31440 this.fireEvent("resize", this, size.width, size.height, e);
31444 updateChildSize : function(){
31446 if(this.resizeChild){
31448 var child = this.resizeChild;
31449 var adj = this.adjustments;
31450 if(el.dom.offsetWidth){
31451 var b = el.getSize(true);
31452 child.setSize(b.width+adj[0], b.height+adj[1]);
31454 // Second call here for IE
31455 // The first call enables instant resizing and
31456 // the second call corrects scroll bars if they
31459 setTimeout(function(){
31460 if(el.dom.offsetWidth){
31461 var b = el.getSize(true);
31462 child.setSize(b.width+adj[0], b.height+adj[1]);
31470 snap : function(value, inc, min){
31471 if(!inc || !value) {
31474 var newValue = value;
31475 var m = value % inc;
31478 newValue = value + (inc-m);
31480 newValue = value - m;
31483 return Math.max(min, newValue);
31487 resizeElement : function(){
31488 var box = this.proxy.getBox();
31489 if(this.updateBox){
31490 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31492 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31494 this.updateChildSize();
31502 constrain : function(v, diff, m, mx){
31505 }else if(v - diff > mx){
31512 onMouseMove : function(e){
31515 try{// try catch so if something goes wrong the user doesn't get hung
31517 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31521 //var curXY = this.startPoint;
31522 var curSize = this.curSize || this.startBox;
31523 var x = this.startBox.x, y = this.startBox.y;
31524 var ox = x, oy = y;
31525 var w = curSize.width, h = curSize.height;
31526 var ow = w, oh = h;
31527 var mw = this.minWidth, mh = this.minHeight;
31528 var mxw = this.maxWidth, mxh = this.maxHeight;
31529 var wi = this.widthIncrement;
31530 var hi = this.heightIncrement;
31532 var eventXY = e.getXY();
31533 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31534 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31536 var pos = this.activeHandle.position;
31541 w = Math.min(Math.max(mw, w), mxw);
31546 h = Math.min(Math.max(mh, h), mxh);
31551 w = Math.min(Math.max(mw, w), mxw);
31552 h = Math.min(Math.max(mh, h), mxh);
31555 diffY = this.constrain(h, diffY, mh, mxh);
31562 var adiffX = Math.abs(diffX);
31563 var sub = (adiffX % wi); // how much
31564 if (sub > (wi/2)) { // far enough to snap
31565 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31567 // remove difference..
31568 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31572 x = Math.max(this.minX, x);
31575 diffX = this.constrain(w, diffX, mw, mxw);
31581 w = Math.min(Math.max(mw, w), mxw);
31582 diffY = this.constrain(h, diffY, mh, mxh);
31587 diffX = this.constrain(w, diffX, mw, mxw);
31588 diffY = this.constrain(h, diffY, mh, mxh);
31595 diffX = this.constrain(w, diffX, mw, mxw);
31597 h = Math.min(Math.max(mh, h), mxh);
31603 var sw = this.snap(w, wi, mw);
31604 var sh = this.snap(h, hi, mh);
31605 if(sw != w || sh != h){
31628 if(this.preserveRatio){
31633 h = Math.min(Math.max(mh, h), mxh);
31638 w = Math.min(Math.max(mw, w), mxw);
31643 w = Math.min(Math.max(mw, w), mxw);
31649 w = Math.min(Math.max(mw, w), mxw);
31655 h = Math.min(Math.max(mh, h), mxh);
31663 h = Math.min(Math.max(mh, h), mxh);
31673 h = Math.min(Math.max(mh, h), mxh);
31681 if (pos == 'hdrag') {
31684 this.proxy.setBounds(x, y, w, h);
31686 this.resizeElement();
31690 this.fireEvent("resizing", this, x, y, w, h, e);
31694 handleOver : function(){
31696 this.el.addClass("x-resizable-over");
31701 handleOut : function(){
31702 if(!this.resizing){
31703 this.el.removeClass("x-resizable-over");
31708 * Returns the element this component is bound to.
31709 * @return {Roo.Element}
31711 getEl : function(){
31716 * Returns the resizeChild element (or null).
31717 * @return {Roo.Element}
31719 getResizeChild : function(){
31720 return this.resizeChild;
31722 groupHandler : function()
31727 * Destroys this resizable. If the element was wrapped and
31728 * removeEl is not true then the element remains.
31729 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31731 destroy : function(removeEl){
31732 this.proxy.remove();
31734 this.overlay.removeAllListeners();
31735 this.overlay.remove();
31737 var ps = Roo.Resizable.positions;
31739 if(typeof ps[k] != "function" && this[ps[k]]){
31740 var h = this[ps[k]];
31741 h.el.removeAllListeners();
31746 this.el.update("");
31753 // hash to map config positions to true positions
31754 Roo.Resizable.positions = {
31755 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31760 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31762 // only initialize the template if resizable is used
31763 var tpl = Roo.DomHelper.createTemplate(
31764 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31767 Roo.Resizable.Handle.prototype.tpl = tpl;
31769 this.position = pos;
31771 // show north drag fro topdra
31772 var handlepos = pos == 'hdrag' ? 'north' : pos;
31774 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31775 if (pos == 'hdrag') {
31776 this.el.setStyle('cursor', 'pointer');
31778 this.el.unselectable();
31780 this.el.setOpacity(0);
31782 this.el.on("mousedown", this.onMouseDown, this);
31783 if(!disableTrackOver){
31784 this.el.on("mouseover", this.onMouseOver, this);
31785 this.el.on("mouseout", this.onMouseOut, this);
31790 Roo.Resizable.Handle.prototype = {
31791 afterResize : function(rz){
31796 onMouseDown : function(e){
31797 this.rz.onMouseDown(this, e);
31800 onMouseOver : function(e){
31801 this.rz.handleOver(this, e);
31804 onMouseOut : function(e){
31805 this.rz.handleOut(this, e);
31809 * Ext JS Library 1.1.1
31810 * Copyright(c) 2006-2007, Ext JS, LLC.
31812 * Originally Released Under LGPL - original licence link has changed is not relivant.
31815 * <script type="text/javascript">
31819 * @class Roo.Editor
31820 * @extends Roo.Component
31821 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31823 * Create a new Editor
31824 * @param {Roo.form.Field} field The Field object (or descendant)
31825 * @param {Object} config The config object
31827 Roo.Editor = function(field, config){
31828 Roo.Editor.superclass.constructor.call(this, config);
31829 this.field = field;
31832 * @event beforestartedit
31833 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31834 * false from the handler of this event.
31835 * @param {Editor} this
31836 * @param {Roo.Element} boundEl The underlying element bound to this editor
31837 * @param {Mixed} value The field value being set
31839 "beforestartedit" : true,
31842 * Fires when this editor is displayed
31843 * @param {Roo.Element} boundEl The underlying element bound to this editor
31844 * @param {Mixed} value The starting field value
31846 "startedit" : true,
31848 * @event beforecomplete
31849 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31850 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31851 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31852 * event will not fire since no edit actually occurred.
31853 * @param {Editor} this
31854 * @param {Mixed} value The current field value
31855 * @param {Mixed} startValue The original field value
31857 "beforecomplete" : true,
31860 * Fires after editing is complete and any changed value has been written to the underlying field.
31861 * @param {Editor} this
31862 * @param {Mixed} value The current field value
31863 * @param {Mixed} startValue The original field value
31867 * @event specialkey
31868 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31869 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31870 * @param {Roo.form.Field} this
31871 * @param {Roo.EventObject} e The event object
31873 "specialkey" : true
31877 Roo.extend(Roo.Editor, Roo.Component, {
31879 * @cfg {Boolean/String} autosize
31880 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31881 * or "height" to adopt the height only (defaults to false)
31884 * @cfg {Boolean} revertInvalid
31885 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31886 * validation fails (defaults to true)
31889 * @cfg {Boolean} ignoreNoChange
31890 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31891 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31892 * will never be ignored.
31895 * @cfg {Boolean} hideEl
31896 * False to keep the bound element visible while the editor is displayed (defaults to true)
31899 * @cfg {Mixed} value
31900 * The data value of the underlying field (defaults to "")
31904 * @cfg {String} alignment
31905 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31909 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31910 * for bottom-right shadow (defaults to "frame")
31914 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31918 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31920 completeOnEnter : false,
31922 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31924 cancelOnEsc : false,
31926 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31931 onRender : function(ct, position){
31932 this.el = new Roo.Layer({
31933 shadow: this.shadow,
31939 constrain: this.constrain
31941 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31942 if(this.field.msgTarget != 'title'){
31943 this.field.msgTarget = 'qtip';
31945 this.field.render(this.el);
31947 this.field.el.dom.setAttribute('autocomplete', 'off');
31949 this.field.on("specialkey", this.onSpecialKey, this);
31950 if(this.swallowKeys){
31951 this.field.el.swallowEvent(['keydown','keypress']);
31954 this.field.on("blur", this.onBlur, this);
31955 if(this.field.grow){
31956 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31960 onSpecialKey : function(field, e)
31962 //Roo.log('editor onSpecialKey');
31963 if(this.completeOnEnter && e.getKey() == e.ENTER){
31965 this.completeEdit();
31968 // do not fire special key otherwise it might hide close the editor...
31969 if(e.getKey() == e.ENTER){
31972 if(this.cancelOnEsc && e.getKey() == e.ESC){
31976 this.fireEvent('specialkey', field, e);
31981 * Starts the editing process and shows the editor.
31982 * @param {String/HTMLElement/Element} el The element to edit
31983 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31984 * to the innerHTML of el.
31986 startEdit : function(el, value){
31988 this.completeEdit();
31990 this.boundEl = Roo.get(el);
31991 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31992 if(!this.rendered){
31993 this.render(this.parentEl || document.body);
31995 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31998 this.startValue = v;
31999 this.field.setValue(v);
32001 var sz = this.boundEl.getSize();
32002 switch(this.autoSize){
32004 this.setSize(sz.width, "");
32007 this.setSize("", sz.height);
32010 this.setSize(sz.width, sz.height);
32013 this.el.alignTo(this.boundEl, this.alignment);
32014 this.editing = true;
32016 Roo.QuickTips.disable();
32022 * Sets the height and width of this editor.
32023 * @param {Number} width The new width
32024 * @param {Number} height The new height
32026 setSize : function(w, h){
32027 this.field.setSize(w, h);
32034 * Realigns the editor to the bound field based on the current alignment config value.
32036 realign : function(){
32037 this.el.alignTo(this.boundEl, this.alignment);
32041 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
32042 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
32044 completeEdit : function(remainVisible){
32048 var v = this.getValue();
32049 if(this.revertInvalid !== false && !this.field.isValid()){
32050 v = this.startValue;
32051 this.cancelEdit(true);
32053 if(String(v) === String(this.startValue) && this.ignoreNoChange){
32054 this.editing = false;
32058 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
32059 this.editing = false;
32060 if(this.updateEl && this.boundEl){
32061 this.boundEl.update(v);
32063 if(remainVisible !== true){
32066 this.fireEvent("complete", this, v, this.startValue);
32071 onShow : function(){
32073 if(this.hideEl !== false){
32074 this.boundEl.hide();
32077 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
32078 this.fixIEFocus = true;
32079 this.deferredFocus.defer(50, this);
32081 this.field.focus();
32083 this.fireEvent("startedit", this.boundEl, this.startValue);
32086 deferredFocus : function(){
32088 this.field.focus();
32093 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
32094 * reverted to the original starting value.
32095 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
32096 * cancel (defaults to false)
32098 cancelEdit : function(remainVisible){
32100 this.setValue(this.startValue);
32101 if(remainVisible !== true){
32108 onBlur : function(){
32109 if(this.allowBlur !== true && this.editing){
32110 this.completeEdit();
32115 onHide : function(){
32117 this.completeEdit();
32121 if(this.field.collapse){
32122 this.field.collapse();
32125 if(this.hideEl !== false){
32126 this.boundEl.show();
32129 Roo.QuickTips.enable();
32134 * Sets the data value of the editor
32135 * @param {Mixed} value Any valid value supported by the underlying field
32137 setValue : function(v){
32138 this.field.setValue(v);
32142 * Gets the data value of the editor
32143 * @return {Mixed} The data value
32145 getValue : function(){
32146 return this.field.getValue();
32150 * Ext JS Library 1.1.1
32151 * Copyright(c) 2006-2007, Ext JS, LLC.
32153 * Originally Released Under LGPL - original licence link has changed is not relivant.
32156 * <script type="text/javascript">
32160 * @class Roo.BasicDialog
32161 * @extends Roo.util.Observable
32162 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32164 var dlg = new Roo.BasicDialog("my-dlg", {
32173 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32174 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32175 dlg.addButton('Cancel', dlg.hide, dlg);
32178 <b>A Dialog should always be a direct child of the body element.</b>
32179 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32180 * @cfg {String} title Default text to display in the title bar (defaults to null)
32181 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32182 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32183 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32184 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32185 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32186 * (defaults to null with no animation)
32187 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32188 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32189 * property for valid values (defaults to 'all')
32190 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32191 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32192 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32193 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32194 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32195 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32196 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32197 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32198 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32199 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32200 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32201 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32202 * draggable = true (defaults to false)
32203 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32204 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32205 * shadow (defaults to false)
32206 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32207 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32208 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32209 * @cfg {Array} buttons Array of buttons
32210 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32212 * Create a new BasicDialog.
32213 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32214 * @param {Object} config Configuration options
32216 Roo.BasicDialog = function(el, config){
32217 this.el = Roo.get(el);
32218 var dh = Roo.DomHelper;
32219 if(!this.el && config && config.autoCreate){
32220 if(typeof config.autoCreate == "object"){
32221 if(!config.autoCreate.id){
32222 config.autoCreate.id = el;
32224 this.el = dh.append(document.body,
32225 config.autoCreate, true);
32227 this.el = dh.append(document.body,
32228 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32232 el.setDisplayed(true);
32233 el.hide = this.hideAction;
32235 el.addClass("x-dlg");
32237 Roo.apply(this, config);
32239 this.proxy = el.createProxy("x-dlg-proxy");
32240 this.proxy.hide = this.hideAction;
32241 this.proxy.setOpacity(.5);
32245 el.setWidth(config.width);
32248 el.setHeight(config.height);
32250 this.size = el.getSize();
32251 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32252 this.xy = [config.x,config.y];
32254 this.xy = el.getCenterXY(true);
32256 /** The header element @type Roo.Element */
32257 this.header = el.child("> .x-dlg-hd");
32258 /** The body element @type Roo.Element */
32259 this.body = el.child("> .x-dlg-bd");
32260 /** The footer element @type Roo.Element */
32261 this.footer = el.child("> .x-dlg-ft");
32264 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32267 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32270 this.header.unselectable();
32272 this.header.update(this.title);
32274 // this element allows the dialog to be focused for keyboard event
32275 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32276 this.focusEl.swallowEvent("click", true);
32278 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32280 // wrap the body and footer for special rendering
32281 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32283 this.bwrap.dom.appendChild(this.footer.dom);
32286 this.bg = this.el.createChild({
32287 tag: "div", cls:"x-dlg-bg",
32288 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32290 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32293 if(this.autoScroll !== false && !this.autoTabs){
32294 this.body.setStyle("overflow", "auto");
32297 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32299 if(this.closable !== false){
32300 this.el.addClass("x-dlg-closable");
32301 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32302 this.close.on("click", this.closeClick, this);
32303 this.close.addClassOnOver("x-dlg-close-over");
32305 if(this.collapsible !== false){
32306 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32307 this.collapseBtn.on("click", this.collapseClick, this);
32308 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32309 this.header.on("dblclick", this.collapseClick, this);
32311 if(this.resizable !== false){
32312 this.el.addClass("x-dlg-resizable");
32313 this.resizer = new Roo.Resizable(el, {
32314 minWidth: this.minWidth || 80,
32315 minHeight:this.minHeight || 80,
32316 handles: this.resizeHandles || "all",
32319 this.resizer.on("beforeresize", this.beforeResize, this);
32320 this.resizer.on("resize", this.onResize, this);
32322 if(this.draggable !== false){
32323 el.addClass("x-dlg-draggable");
32324 if (!this.proxyDrag) {
32325 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32328 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32330 dd.setHandleElId(this.header.id);
32331 dd.endDrag = this.endMove.createDelegate(this);
32332 dd.startDrag = this.startMove.createDelegate(this);
32333 dd.onDrag = this.onDrag.createDelegate(this);
32338 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32339 this.mask.enableDisplayMode("block");
32341 this.el.addClass("x-dlg-modal");
32344 this.shadow = new Roo.Shadow({
32345 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32346 offset : this.shadowOffset
32349 this.shadowOffset = 0;
32351 if(Roo.useShims && this.shim !== false){
32352 this.shim = this.el.createShim();
32353 this.shim.hide = this.hideAction;
32361 if (this.buttons) {
32362 var bts= this.buttons;
32364 Roo.each(bts, function(b) {
32373 * Fires when a key is pressed
32374 * @param {Roo.BasicDialog} this
32375 * @param {Roo.EventObject} e
32380 * Fires when this dialog is moved by the user.
32381 * @param {Roo.BasicDialog} this
32382 * @param {Number} x The new page X
32383 * @param {Number} y The new page Y
32388 * Fires when this dialog is resized by the user.
32389 * @param {Roo.BasicDialog} this
32390 * @param {Number} width The new width
32391 * @param {Number} height The new height
32395 * @event beforehide
32396 * Fires before this dialog is hidden.
32397 * @param {Roo.BasicDialog} this
32399 "beforehide" : true,
32402 * Fires when this dialog is hidden.
32403 * @param {Roo.BasicDialog} this
32407 * @event beforeshow
32408 * Fires before this dialog is shown.
32409 * @param {Roo.BasicDialog} this
32411 "beforeshow" : true,
32414 * Fires when this dialog is shown.
32415 * @param {Roo.BasicDialog} this
32419 el.on("keydown", this.onKeyDown, this);
32420 el.on("mousedown", this.toFront, this);
32421 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32423 Roo.DialogManager.register(this);
32424 Roo.BasicDialog.superclass.constructor.call(this);
32427 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32428 shadowOffset: Roo.isIE ? 6 : 5,
32431 minButtonWidth: 75,
32432 defaultButton: null,
32433 buttonAlign: "right",
32438 * Sets the dialog title text
32439 * @param {String} text The title text to display
32440 * @return {Roo.BasicDialog} this
32442 setTitle : function(text){
32443 this.header.update(text);
32448 closeClick : function(){
32453 collapseClick : function(){
32454 this[this.collapsed ? "expand" : "collapse"]();
32458 * Collapses the dialog to its minimized state (only the title bar is visible).
32459 * Equivalent to the user clicking the collapse dialog button.
32461 collapse : function(){
32462 if(!this.collapsed){
32463 this.collapsed = true;
32464 this.el.addClass("x-dlg-collapsed");
32465 this.restoreHeight = this.el.getHeight();
32466 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32471 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32472 * clicking the expand dialog button.
32474 expand : function(){
32475 if(this.collapsed){
32476 this.collapsed = false;
32477 this.el.removeClass("x-dlg-collapsed");
32478 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32483 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32484 * @return {Roo.TabPanel} The tabs component
32486 initTabs : function(){
32487 var tabs = this.getTabs();
32488 while(tabs.getTab(0)){
32491 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32493 tabs.addTab(Roo.id(dom), dom.title);
32501 beforeResize : function(){
32502 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32506 onResize : function(){
32507 this.refreshSize();
32508 this.syncBodyHeight();
32509 this.adjustAssets();
32511 this.fireEvent("resize", this, this.size.width, this.size.height);
32515 onKeyDown : function(e){
32516 if(this.isVisible()){
32517 this.fireEvent("keydown", this, e);
32522 * Resizes the dialog.
32523 * @param {Number} width
32524 * @param {Number} height
32525 * @return {Roo.BasicDialog} this
32527 resizeTo : function(width, height){
32528 this.el.setSize(width, height);
32529 this.size = {width: width, height: height};
32530 this.syncBodyHeight();
32531 if(this.fixedcenter){
32534 if(this.isVisible()){
32535 this.constrainXY();
32536 this.adjustAssets();
32538 this.fireEvent("resize", this, width, height);
32544 * Resizes the dialog to fit the specified content size.
32545 * @param {Number} width
32546 * @param {Number} height
32547 * @return {Roo.BasicDialog} this
32549 setContentSize : function(w, h){
32550 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32551 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32552 //if(!this.el.isBorderBox()){
32553 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32554 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32557 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32558 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32560 this.resizeTo(w, h);
32565 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32566 * executed in response to a particular key being pressed while the dialog is active.
32567 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32568 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32569 * @param {Function} fn The function to call
32570 * @param {Object} scope (optional) The scope of the function
32571 * @return {Roo.BasicDialog} this
32573 addKeyListener : function(key, fn, scope){
32574 var keyCode, shift, ctrl, alt;
32575 if(typeof key == "object" && !(key instanceof Array)){
32576 keyCode = key["key"];
32577 shift = key["shift"];
32578 ctrl = key["ctrl"];
32583 var handler = function(dlg, e){
32584 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32585 var k = e.getKey();
32586 if(keyCode instanceof Array){
32587 for(var i = 0, len = keyCode.length; i < len; i++){
32588 if(keyCode[i] == k){
32589 fn.call(scope || window, dlg, k, e);
32595 fn.call(scope || window, dlg, k, e);
32600 this.on("keydown", handler);
32605 * Returns the TabPanel component (creates it if it doesn't exist).
32606 * Note: If you wish to simply check for the existence of tabs without creating them,
32607 * check for a null 'tabs' property.
32608 * @return {Roo.TabPanel} The tabs component
32610 getTabs : function(){
32612 this.el.addClass("x-dlg-auto-tabs");
32613 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32614 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32620 * Adds a button to the footer section of the dialog.
32621 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32622 * object or a valid Roo.DomHelper element config
32623 * @param {Function} handler The function called when the button is clicked
32624 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32625 * @return {Roo.Button} The new button
32627 addButton : function(config, handler, scope){
32628 var dh = Roo.DomHelper;
32630 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32632 if(!this.btnContainer){
32633 var tb = this.footer.createChild({
32635 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32636 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32638 this.btnContainer = tb.firstChild.firstChild.firstChild;
32643 minWidth: this.minButtonWidth,
32646 if(typeof config == "string"){
32647 bconfig.text = config;
32650 bconfig.dhconfig = config;
32652 Roo.apply(bconfig, config);
32656 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32657 bconfig.position = Math.max(0, bconfig.position);
32658 fc = this.btnContainer.childNodes[bconfig.position];
32661 var btn = new Roo.Button(
32663 this.btnContainer.insertBefore(document.createElement("td"),fc)
32664 : this.btnContainer.appendChild(document.createElement("td")),
32665 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32668 this.syncBodyHeight();
32671 * Array of all the buttons that have been added to this dialog via addButton
32676 this.buttons.push(btn);
32681 * Sets the default button to be focused when the dialog is displayed.
32682 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32683 * @return {Roo.BasicDialog} this
32685 setDefaultButton : function(btn){
32686 this.defaultButton = btn;
32691 getHeaderFooterHeight : function(safe){
32694 height += this.header.getHeight();
32697 var fm = this.footer.getMargins();
32698 height += (this.footer.getHeight()+fm.top+fm.bottom);
32700 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32701 height += this.centerBg.getPadding("tb");
32706 syncBodyHeight : function()
32708 var bd = this.body, // the text
32709 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32711 var height = this.size.height - this.getHeaderFooterHeight(false);
32712 bd.setHeight(height-bd.getMargins("tb"));
32713 var hh = this.header.getHeight();
32714 var h = this.size.height-hh;
32717 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32718 bw.setHeight(h-cb.getPadding("tb"));
32720 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32721 bd.setWidth(bw.getWidth(true));
32723 this.tabs.syncHeight();
32725 this.tabs.el.repaint();
32731 * Restores the previous state of the dialog if Roo.state is configured.
32732 * @return {Roo.BasicDialog} this
32734 restoreState : function(){
32735 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32736 if(box && box.width){
32737 this.xy = [box.x, box.y];
32738 this.resizeTo(box.width, box.height);
32744 beforeShow : function(){
32746 if(this.fixedcenter){
32747 this.xy = this.el.getCenterXY(true);
32750 Roo.get(document.body).addClass("x-body-masked");
32751 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32754 this.constrainXY();
32758 animShow : function(){
32759 var b = Roo.get(this.animateTarget).getBox();
32760 this.proxy.setSize(b.width, b.height);
32761 this.proxy.setLocation(b.x, b.y);
32763 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32764 true, .35, this.showEl.createDelegate(this));
32768 * Shows the dialog.
32769 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32770 * @return {Roo.BasicDialog} this
32772 show : function(animateTarget){
32773 if (this.fireEvent("beforeshow", this) === false){
32776 if(this.syncHeightBeforeShow){
32777 this.syncBodyHeight();
32778 }else if(this.firstShow){
32779 this.firstShow = false;
32780 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32782 this.animateTarget = animateTarget || this.animateTarget;
32783 if(!this.el.isVisible()){
32785 if(this.animateTarget && Roo.get(this.animateTarget)){
32795 showEl : function(){
32797 this.el.setXY(this.xy);
32799 this.adjustAssets(true);
32802 // IE peekaboo bug - fix found by Dave Fenwick
32806 this.fireEvent("show", this);
32810 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32811 * dialog itself will receive focus.
32813 focus : function(){
32814 if(this.defaultButton){
32815 this.defaultButton.focus();
32817 this.focusEl.focus();
32822 constrainXY : function(){
32823 if(this.constraintoviewport !== false){
32824 if(!this.viewSize){
32825 if(this.container){
32826 var s = this.container.getSize();
32827 this.viewSize = [s.width, s.height];
32829 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32832 var s = Roo.get(this.container||document).getScroll();
32834 var x = this.xy[0], y = this.xy[1];
32835 var w = this.size.width, h = this.size.height;
32836 var vw = this.viewSize[0], vh = this.viewSize[1];
32837 // only move it if it needs it
32839 // first validate right/bottom
32840 if(x + w > vw+s.left){
32844 if(y + h > vh+s.top){
32848 // then make sure top/left isn't negative
32860 if(this.isVisible()){
32861 this.el.setLocation(x, y);
32862 this.adjustAssets();
32869 onDrag : function(){
32870 if(!this.proxyDrag){
32871 this.xy = this.el.getXY();
32872 this.adjustAssets();
32877 adjustAssets : function(doShow){
32878 var x = this.xy[0], y = this.xy[1];
32879 var w = this.size.width, h = this.size.height;
32880 if(doShow === true){
32882 this.shadow.show(this.el);
32888 if(this.shadow && this.shadow.isVisible()){
32889 this.shadow.show(this.el);
32891 if(this.shim && this.shim.isVisible()){
32892 this.shim.setBounds(x, y, w, h);
32897 adjustViewport : function(w, h){
32899 w = Roo.lib.Dom.getViewWidth();
32900 h = Roo.lib.Dom.getViewHeight();
32903 this.viewSize = [w, h];
32904 if(this.modal && this.mask.isVisible()){
32905 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32906 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32908 if(this.isVisible()){
32909 this.constrainXY();
32914 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32915 * shadow, proxy, mask, etc.) Also removes all event listeners.
32916 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32918 destroy : function(removeEl){
32919 if(this.isVisible()){
32920 this.animateTarget = null;
32923 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32925 this.tabs.destroy(removeEl);
32938 for(var i = 0, len = this.buttons.length; i < len; i++){
32939 this.buttons[i].destroy();
32942 this.el.removeAllListeners();
32943 if(removeEl === true){
32944 this.el.update("");
32947 Roo.DialogManager.unregister(this);
32951 startMove : function(){
32952 if(this.proxyDrag){
32955 if(this.constraintoviewport !== false){
32956 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32961 endMove : function(){
32962 if(!this.proxyDrag){
32963 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32965 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32968 this.refreshSize();
32969 this.adjustAssets();
32971 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32975 * Brings this dialog to the front of any other visible dialogs
32976 * @return {Roo.BasicDialog} this
32978 toFront : function(){
32979 Roo.DialogManager.bringToFront(this);
32984 * Sends this dialog to the back (under) of any other visible dialogs
32985 * @return {Roo.BasicDialog} this
32987 toBack : function(){
32988 Roo.DialogManager.sendToBack(this);
32993 * Centers this dialog in the viewport
32994 * @return {Roo.BasicDialog} this
32996 center : function(){
32997 var xy = this.el.getCenterXY(true);
32998 this.moveTo(xy[0], xy[1]);
33003 * Moves the dialog's top-left corner to the specified point
33004 * @param {Number} x
33005 * @param {Number} y
33006 * @return {Roo.BasicDialog} this
33008 moveTo : function(x, y){
33010 if(this.isVisible()){
33011 this.el.setXY(this.xy);
33012 this.adjustAssets();
33018 * Aligns the dialog to the specified element
33019 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33020 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
33021 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33022 * @return {Roo.BasicDialog} this
33024 alignTo : function(element, position, offsets){
33025 this.xy = this.el.getAlignToXY(element, position, offsets);
33026 if(this.isVisible()){
33027 this.el.setXY(this.xy);
33028 this.adjustAssets();
33034 * Anchors an element to another element and realigns it when the window is resized.
33035 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33036 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
33037 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33038 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
33039 * is a number, it is used as the buffer delay (defaults to 50ms).
33040 * @return {Roo.BasicDialog} this
33042 anchorTo : function(el, alignment, offsets, monitorScroll){
33043 var action = function(){
33044 this.alignTo(el, alignment, offsets);
33046 Roo.EventManager.onWindowResize(action, this);
33047 var tm = typeof monitorScroll;
33048 if(tm != 'undefined'){
33049 Roo.EventManager.on(window, 'scroll', action, this,
33050 {buffer: tm == 'number' ? monitorScroll : 50});
33057 * Returns true if the dialog is visible
33058 * @return {Boolean}
33060 isVisible : function(){
33061 return this.el.isVisible();
33065 animHide : function(callback){
33066 var b = Roo.get(this.animateTarget).getBox();
33068 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
33070 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
33071 this.hideEl.createDelegate(this, [callback]));
33075 * Hides the dialog.
33076 * @param {Function} callback (optional) Function to call when the dialog is hidden
33077 * @return {Roo.BasicDialog} this
33079 hide : function(callback){
33080 if (this.fireEvent("beforehide", this) === false){
33084 this.shadow.hide();
33089 // sometimes animateTarget seems to get set.. causing problems...
33090 // this just double checks..
33091 if(this.animateTarget && Roo.get(this.animateTarget)) {
33092 this.animHide(callback);
33095 this.hideEl(callback);
33101 hideEl : function(callback){
33105 Roo.get(document.body).removeClass("x-body-masked");
33107 this.fireEvent("hide", this);
33108 if(typeof callback == "function"){
33114 hideAction : function(){
33115 this.setLeft("-10000px");
33116 this.setTop("-10000px");
33117 this.setStyle("visibility", "hidden");
33121 refreshSize : function(){
33122 this.size = this.el.getSize();
33123 this.xy = this.el.getXY();
33124 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
33128 // z-index is managed by the DialogManager and may be overwritten at any time
33129 setZIndex : function(index){
33131 this.mask.setStyle("z-index", index);
33134 this.shim.setStyle("z-index", ++index);
33137 this.shadow.setZIndex(++index);
33139 this.el.setStyle("z-index", ++index);
33141 this.proxy.setStyle("z-index", ++index);
33144 this.resizer.proxy.setStyle("z-index", ++index);
33147 this.lastZIndex = index;
33151 * Returns the element for this dialog
33152 * @return {Roo.Element} The underlying dialog Element
33154 getEl : function(){
33160 * @class Roo.DialogManager
33161 * Provides global access to BasicDialogs that have been created and
33162 * support for z-indexing (layering) multiple open dialogs.
33164 Roo.DialogManager = function(){
33166 var accessList = [];
33170 var sortDialogs = function(d1, d2){
33171 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33175 var orderDialogs = function(){
33176 accessList.sort(sortDialogs);
33177 var seed = Roo.DialogManager.zseed;
33178 for(var i = 0, len = accessList.length; i < len; i++){
33179 var dlg = accessList[i];
33181 dlg.setZIndex(seed + (i*10));
33188 * The starting z-index for BasicDialogs (defaults to 9000)
33189 * @type Number The z-index value
33194 register : function(dlg){
33195 list[dlg.id] = dlg;
33196 accessList.push(dlg);
33200 unregister : function(dlg){
33201 delete list[dlg.id];
33204 if(!accessList.indexOf){
33205 for( i = 0, len = accessList.length; i < len; i++){
33206 if(accessList[i] == dlg){
33207 accessList.splice(i, 1);
33212 i = accessList.indexOf(dlg);
33214 accessList.splice(i, 1);
33220 * Gets a registered dialog by id
33221 * @param {String/Object} id The id of the dialog or a dialog
33222 * @return {Roo.BasicDialog} this
33224 get : function(id){
33225 return typeof id == "object" ? id : list[id];
33229 * Brings the specified dialog to the front
33230 * @param {String/Object} dlg The id of the dialog or a dialog
33231 * @return {Roo.BasicDialog} this
33233 bringToFront : function(dlg){
33234 dlg = this.get(dlg);
33237 dlg._lastAccess = new Date().getTime();
33244 * Sends the specified dialog to the back
33245 * @param {String/Object} dlg The id of the dialog or a dialog
33246 * @return {Roo.BasicDialog} this
33248 sendToBack : function(dlg){
33249 dlg = this.get(dlg);
33250 dlg._lastAccess = -(new Date().getTime());
33256 * Hides all dialogs
33258 hideAll : function(){
33259 for(var id in list){
33260 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33269 * @class Roo.LayoutDialog
33270 * @extends Roo.BasicDialog
33271 * @children Roo.ContentPanel
33272 * @parent builder none
33273 * Dialog which provides adjustments for working with a layout in a Dialog.
33274 * Add your necessary layout config options to the dialog's config.<br>
33275 * Example usage (including a nested layout):
33278 dialog = new Roo.LayoutDialog("download-dlg", {
33287 // layout config merges with the dialog config
33289 tabPosition: "top",
33290 alwaysShowTabs: true
33293 dialog.addKeyListener(27, dialog.hide, dialog);
33294 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33295 dialog.addButton("Build It!", this.getDownload, this);
33297 // we can even add nested layouts
33298 var innerLayout = new Roo.BorderLayout("dl-inner", {
33308 innerLayout.beginUpdate();
33309 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33310 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33311 innerLayout.endUpdate(true);
33313 var layout = dialog.getLayout();
33314 layout.beginUpdate();
33315 layout.add("center", new Roo.ContentPanel("standard-panel",
33316 {title: "Download the Source", fitToFrame:true}));
33317 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33318 {title: "Build your own roo.js"}));
33319 layout.getRegion("center").showPanel(sp);
33320 layout.endUpdate();
33324 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33325 * @param {Object} config configuration options
33327 Roo.LayoutDialog = function(el, cfg){
33330 if (typeof(cfg) == 'undefined') {
33331 config = Roo.apply({}, el);
33332 // not sure why we use documentElement here.. - it should always be body.
33333 // IE7 borks horribly if we use documentElement.
33334 // webkit also does not like documentElement - it creates a body element...
33335 el = Roo.get( document.body || document.documentElement ).createChild();
33336 //config.autoCreate = true;
33340 config.autoTabs = false;
33341 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33342 this.body.setStyle({overflow:"hidden", position:"relative"});
33343 this.layout = new Roo.BorderLayout(this.body.dom, config);
33344 this.layout.monitorWindowResize = false;
33345 this.el.addClass("x-dlg-auto-layout");
33346 // fix case when center region overwrites center function
33347 this.center = Roo.BasicDialog.prototype.center;
33348 this.on("show", this.layout.layout, this.layout, true);
33349 if (config.items) {
33350 var xitems = config.items;
33351 delete config.items;
33352 Roo.each(xitems, this.addxtype, this);
33357 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33361 * @cfg {Roo.LayoutRegion} east
33364 * @cfg {Roo.LayoutRegion} west
33367 * @cfg {Roo.LayoutRegion} south
33370 * @cfg {Roo.LayoutRegion} north
33373 * @cfg {Roo.LayoutRegion} center
33376 * @cfg {Roo.Button} buttons[] Bottom buttons..
33381 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33384 endUpdate : function(){
33385 this.layout.endUpdate();
33389 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33392 beginUpdate : function(){
33393 this.layout.beginUpdate();
33397 * Get the BorderLayout for this dialog
33398 * @return {Roo.BorderLayout}
33400 getLayout : function(){
33401 return this.layout;
33404 showEl : function(){
33405 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33407 this.layout.layout();
33412 // Use the syncHeightBeforeShow config option to control this automatically
33413 syncBodyHeight : function(){
33414 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33415 if(this.layout){this.layout.layout();}
33419 * Add an xtype element (actually adds to the layout.)
33420 * @return {Object} xdata xtype object data.
33423 addxtype : function(c) {
33424 return this.layout.addxtype(c);
33428 * Ext JS Library 1.1.1
33429 * Copyright(c) 2006-2007, Ext JS, LLC.
33431 * Originally Released Under LGPL - original licence link has changed is not relivant.
33434 * <script type="text/javascript">
33438 * @class Roo.MessageBox
33439 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33443 Roo.Msg.alert('Status', 'Changes saved successfully.');
33445 // Prompt for user data:
33446 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33448 // process text value...
33452 // Show a dialog using config options:
33454 title:'Save Changes?',
33455 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33456 buttons: Roo.Msg.YESNOCANCEL,
33463 Roo.MessageBox = function(){
33464 var dlg, opt, mask, waitTimer;
33465 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33466 var buttons, activeTextEl, bwidth;
33469 var handleButton = function(button){
33471 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33475 var handleHide = function(){
33476 if(opt && opt.cls){
33477 dlg.el.removeClass(opt.cls);
33480 Roo.TaskMgr.stop(waitTimer);
33486 var updateButtons = function(b){
33489 buttons["ok"].hide();
33490 buttons["cancel"].hide();
33491 buttons["yes"].hide();
33492 buttons["no"].hide();
33493 dlg.footer.dom.style.display = 'none';
33496 dlg.footer.dom.style.display = '';
33497 for(var k in buttons){
33498 if(typeof buttons[k] != "function"){
33501 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33502 width += buttons[k].el.getWidth()+15;
33512 var handleEsc = function(d, k, e){
33513 if(opt && opt.closable !== false){
33523 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33524 * @return {Roo.BasicDialog} The BasicDialog element
33526 getDialog : function(){
33528 dlg = new Roo.BasicDialog("x-msg-box", {
33533 constraintoviewport:false,
33535 collapsible : false,
33538 width:400, height:100,
33539 buttonAlign:"center",
33540 closeClick : function(){
33541 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33542 handleButton("no");
33544 handleButton("cancel");
33548 dlg.on("hide", handleHide);
33550 dlg.addKeyListener(27, handleEsc);
33552 var bt = this.buttonText;
33553 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33554 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33555 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33556 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33557 bodyEl = dlg.body.createChild({
33559 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>'
33561 msgEl = bodyEl.dom.firstChild;
33562 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33563 textboxEl.enableDisplayMode();
33564 textboxEl.addKeyListener([10,13], function(){
33565 if(dlg.isVisible() && opt && opt.buttons){
33566 if(opt.buttons.ok){
33567 handleButton("ok");
33568 }else if(opt.buttons.yes){
33569 handleButton("yes");
33573 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33574 textareaEl.enableDisplayMode();
33575 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33576 progressEl.enableDisplayMode();
33577 var pf = progressEl.dom.firstChild;
33579 pp = Roo.get(pf.firstChild);
33580 pp.setHeight(pf.offsetHeight);
33588 * Updates the message box body text
33589 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33590 * the XHTML-compliant non-breaking space character '&#160;')
33591 * @return {Roo.MessageBox} This message box
33593 updateText : function(text){
33594 if(!dlg.isVisible() && !opt.width){
33595 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33597 msgEl.innerHTML = text || ' ';
33599 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33600 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33602 Math.min(opt.width || cw , this.maxWidth),
33603 Math.max(opt.minWidth || this.minWidth, bwidth)
33606 activeTextEl.setWidth(w);
33608 if(dlg.isVisible()){
33609 dlg.fixedcenter = false;
33611 // to big, make it scroll. = But as usual stupid IE does not support
33614 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33615 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33616 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33618 bodyEl.dom.style.height = '';
33619 bodyEl.dom.style.overflowY = '';
33622 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33624 bodyEl.dom.style.overflowX = '';
33627 dlg.setContentSize(w, bodyEl.getHeight());
33628 if(dlg.isVisible()){
33629 dlg.fixedcenter = true;
33635 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33636 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33637 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33638 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33639 * @return {Roo.MessageBox} This message box
33641 updateProgress : function(value, text){
33643 this.updateText(text);
33645 if (pp) { // weird bug on my firefox - for some reason this is not defined
33646 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33652 * Returns true if the message box is currently displayed
33653 * @return {Boolean} True if the message box is visible, else false
33655 isVisible : function(){
33656 return dlg && dlg.isVisible();
33660 * Hides the message box if it is displayed
33663 if(this.isVisible()){
33669 * Displays a new message box, or reinitializes an existing message box, based on the config options
33670 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33671 * The following config object properties are supported:
33673 Property Type Description
33674 ---------- --------------- ------------------------------------------------------------------------------------
33675 animEl String/Element An id or Element from which the message box should animate as it opens and
33676 closes (defaults to undefined)
33677 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33678 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33679 closable Boolean False to hide the top-right close button (defaults to true). Note that
33680 progress and wait dialogs will ignore this property and always hide the
33681 close button as they can only be closed programmatically.
33682 cls String A custom CSS class to apply to the message box element
33683 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33684 displayed (defaults to 75)
33685 fn Function A callback function to execute after closing the dialog. The arguments to the
33686 function will be btn (the name of the button that was clicked, if applicable,
33687 e.g. "ok"), and text (the value of the active text field, if applicable).
33688 Progress and wait dialogs will ignore this option since they do not respond to
33689 user actions and can only be closed programmatically, so any required function
33690 should be called by the same code after it closes the dialog.
33691 icon String A CSS class that provides a background image to be used as an icon for
33692 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33693 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33694 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33695 modal Boolean False to allow user interaction with the page while the message box is
33696 displayed (defaults to true)
33697 msg String A string that will replace the existing message box body text (defaults
33698 to the XHTML-compliant non-breaking space character ' ')
33699 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33700 progress Boolean True to display a progress bar (defaults to false)
33701 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33702 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33703 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33704 title String The title text
33705 value String The string value to set into the active textbox element if displayed
33706 wait Boolean True to display a progress bar (defaults to false)
33707 width Number The width of the dialog in pixels
33714 msg: 'Please enter your address:',
33716 buttons: Roo.MessageBox.OKCANCEL,
33719 animEl: 'addAddressBtn'
33722 * @param {Object} config Configuration options
33723 * @return {Roo.MessageBox} This message box
33725 show : function(options)
33728 // this causes nightmares if you show one dialog after another
33729 // especially on callbacks..
33731 if(this.isVisible()){
33734 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33735 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33736 Roo.log("New Dialog Message:" + options.msg )
33737 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33738 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33741 var d = this.getDialog();
33743 d.setTitle(opt.title || " ");
33744 d.close.setDisplayed(opt.closable !== false);
33745 activeTextEl = textboxEl;
33746 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33751 textareaEl.setHeight(typeof opt.multiline == "number" ?
33752 opt.multiline : this.defaultTextHeight);
33753 activeTextEl = textareaEl;
33762 progressEl.setDisplayed(opt.progress === true);
33763 this.updateProgress(0);
33764 activeTextEl.dom.value = opt.value || "";
33766 dlg.setDefaultButton(activeTextEl);
33768 var bs = opt.buttons;
33771 db = buttons["ok"];
33772 }else if(bs && bs.yes){
33773 db = buttons["yes"];
33775 dlg.setDefaultButton(db);
33777 bwidth = updateButtons(opt.buttons);
33778 this.updateText(opt.msg);
33780 d.el.addClass(opt.cls);
33782 d.proxyDrag = opt.proxyDrag === true;
33783 d.modal = opt.modal !== false;
33784 d.mask = opt.modal !== false ? mask : false;
33785 if(!d.isVisible()){
33786 // force it to the end of the z-index stack so it gets a cursor in FF
33787 document.body.appendChild(dlg.el.dom);
33788 d.animateTarget = null;
33789 d.show(options.animEl);
33795 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33796 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33797 * and closing the message box when the process is complete.
33798 * @param {String} title The title bar text
33799 * @param {String} msg The message box body text
33800 * @return {Roo.MessageBox} This message box
33802 progress : function(title, msg){
33809 minWidth: this.minProgressWidth,
33816 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33817 * If a callback function is passed it will be called after the user clicks the button, and the
33818 * id of the button that was clicked will be passed as the only parameter to the callback
33819 * (could also be the top-right close button).
33820 * @param {String} title The title bar text
33821 * @param {String} msg The message box body text
33822 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33823 * @param {Object} scope (optional) The scope of the callback function
33824 * @return {Roo.MessageBox} This message box
33826 alert : function(title, msg, fn, scope){
33839 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33840 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33841 * You are responsible for closing the message box when the process is complete.
33842 * @param {String} msg The message box body text
33843 * @param {String} title (optional) The title bar text
33844 * @return {Roo.MessageBox} This message box
33846 wait : function(msg, title){
33857 waitTimer = Roo.TaskMgr.start({
33859 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33867 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33868 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33869 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33870 * @param {String} title The title bar text
33871 * @param {String} msg The message box body text
33872 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33873 * @param {Object} scope (optional) The scope of the callback function
33874 * @return {Roo.MessageBox} This message box
33876 confirm : function(title, msg, fn, scope){
33880 buttons: this.YESNO,
33889 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33890 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33891 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33892 * (could also be the top-right close button) and the text that was entered will be passed as the two
33893 * parameters to the callback.
33894 * @param {String} title The title bar text
33895 * @param {String} msg The message box body text
33896 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33897 * @param {Object} scope (optional) The scope of the callback function
33898 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33899 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33900 * @return {Roo.MessageBox} This message box
33902 prompt : function(title, msg, fn, scope, multiline){
33906 buttons: this.OKCANCEL,
33911 multiline: multiline,
33918 * Button config that displays a single OK button
33923 * Button config that displays Yes and No buttons
33926 YESNO : {yes:true, no:true},
33928 * Button config that displays OK and Cancel buttons
33931 OKCANCEL : {ok:true, cancel:true},
33933 * Button config that displays Yes, No and Cancel buttons
33936 YESNOCANCEL : {yes:true, no:true, cancel:true},
33939 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33942 defaultTextHeight : 75,
33944 * The maximum width in pixels of the message box (defaults to 600)
33949 * The minimum width in pixels of the message box (defaults to 100)
33954 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33955 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33958 minProgressWidth : 250,
33960 * An object containing the default button text strings that can be overriden for localized language support.
33961 * Supported properties are: ok, cancel, yes and no.
33962 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33975 * Shorthand for {@link Roo.MessageBox}
33977 Roo.Msg = Roo.MessageBox;/*
33979 * Ext JS Library 1.1.1
33980 * Copyright(c) 2006-2007, Ext JS, LLC.
33982 * Originally Released Under LGPL - original licence link has changed is not relivant.
33985 * <script type="text/javascript">
33988 * @class Roo.QuickTips
33989 * Provides attractive and customizable tooltips for any element.
33992 Roo.QuickTips = function(){
33993 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33994 var ce, bd, xy, dd;
33995 var visible = false, disabled = true, inited = false;
33996 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33998 var onOver = function(e){
34002 var t = e.getTarget();
34003 if(!t || t.nodeType !== 1 || t == document || t == document.body){
34006 if(ce && t == ce.el){
34007 clearTimeout(hideProc);
34010 if(t && tagEls[t.id]){
34011 tagEls[t.id].el = t;
34012 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
34015 var ttp, et = Roo.fly(t);
34016 var ns = cfg.namespace;
34017 if(tm.interceptTitles && t.title){
34020 t.removeAttribute("title");
34021 e.preventDefault();
34023 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
34026 showProc = show.defer(tm.showDelay, tm, [{
34028 text: ttp.replace(/\\n/g,'<br/>'),
34029 width: et.getAttributeNS(ns, cfg.width),
34030 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
34031 title: et.getAttributeNS(ns, cfg.title),
34032 cls: et.getAttributeNS(ns, cfg.cls)
34037 var onOut = function(e){
34038 clearTimeout(showProc);
34039 var t = e.getTarget();
34040 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
34041 hideProc = setTimeout(hide, tm.hideDelay);
34045 var onMove = function(e){
34051 if(tm.trackMouse && ce){
34056 var onDown = function(e){
34057 clearTimeout(showProc);
34058 clearTimeout(hideProc);
34060 if(tm.hideOnClick){
34063 tm.enable.defer(100, tm);
34068 var getPad = function(){
34069 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
34072 var show = function(o){
34076 clearTimeout(dismissProc);
34078 if(removeCls){ // in case manually hidden
34079 el.removeClass(removeCls);
34083 el.addClass(ce.cls);
34084 removeCls = ce.cls;
34087 tipTitle.update(ce.title);
34090 tipTitle.update('');
34093 el.dom.style.width = tm.maxWidth+'px';
34094 //tipBody.dom.style.width = '';
34095 tipBodyText.update(o.text);
34096 var p = getPad(), w = ce.width;
34098 var td = tipBodyText.dom;
34099 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
34100 if(aw > tm.maxWidth){
34102 }else if(aw < tm.minWidth){
34108 //tipBody.setWidth(w);
34109 el.setWidth(parseInt(w, 10) + p);
34110 if(ce.autoHide === false){
34111 close.setDisplayed(true);
34116 close.setDisplayed(false);
34122 el.avoidY = xy[1]-18;
34127 el.setStyle("visibility", "visible");
34128 el.fadeIn({callback: afterShow});
34134 var afterShow = function(){
34138 if(tm.autoDismiss && ce.autoHide !== false){
34139 dismissProc = setTimeout(hide, tm.autoDismissDelay);
34144 var hide = function(noanim){
34145 clearTimeout(dismissProc);
34146 clearTimeout(hideProc);
34148 if(el.isVisible()){
34150 if(noanim !== true && tm.animate){
34151 el.fadeOut({callback: afterHide});
34158 var afterHide = function(){
34161 el.removeClass(removeCls);
34168 * @cfg {Number} minWidth
34169 * The minimum width of the quick tip (defaults to 40)
34173 * @cfg {Number} maxWidth
34174 * The maximum width of the quick tip (defaults to 300)
34178 * @cfg {Boolean} interceptTitles
34179 * True to automatically use the element's DOM title value if available (defaults to false)
34181 interceptTitles : false,
34183 * @cfg {Boolean} trackMouse
34184 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34186 trackMouse : false,
34188 * @cfg {Boolean} hideOnClick
34189 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34191 hideOnClick : true,
34193 * @cfg {Number} showDelay
34194 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
34198 * @cfg {Number} hideDelay
34199 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34203 * @cfg {Boolean} autoHide
34204 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34205 * Used in conjunction with hideDelay.
34210 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34211 * (defaults to true). Used in conjunction with autoDismissDelay.
34213 autoDismiss : true,
34216 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34218 autoDismissDelay : 5000,
34220 * @cfg {Boolean} animate
34221 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34226 * @cfg {String} title
34227 * Title text to display (defaults to ''). This can be any valid HTML markup.
34231 * @cfg {String} text
34232 * Body text to display (defaults to ''). This can be any valid HTML markup.
34236 * @cfg {String} cls
34237 * A CSS class to apply to the base quick tip element (defaults to '').
34241 * @cfg {Number} width
34242 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34243 * minWidth or maxWidth.
34248 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34249 * or display QuickTips in a page.
34252 tm = Roo.QuickTips;
34253 cfg = tm.tagConfig;
34255 if(!Roo.isReady){ // allow calling of init() before onReady
34256 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34259 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34260 el.fxDefaults = {stopFx: true};
34261 // maximum custom styling
34262 //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>');
34263 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>');
34264 tipTitle = el.child('h3');
34265 tipTitle.enableDisplayMode("block");
34266 tipBody = el.child('div.x-tip-bd');
34267 tipBodyText = el.child('div.x-tip-bd-inner');
34268 //bdLeft = el.child('div.x-tip-bd-left');
34269 //bdRight = el.child('div.x-tip-bd-right');
34270 close = el.child('div.x-tip-close');
34271 close.enableDisplayMode("block");
34272 close.on("click", hide);
34273 var d = Roo.get(document);
34274 d.on("mousedown", onDown);
34275 d.on("mouseover", onOver);
34276 d.on("mouseout", onOut);
34277 d.on("mousemove", onMove);
34278 esc = d.addKeyListener(27, hide);
34281 dd = el.initDD("default", null, {
34282 onDrag : function(){
34286 dd.setHandleElId(tipTitle.id);
34295 * Configures a new quick tip instance and assigns it to a target element. The following config options
34298 Property Type Description
34299 ---------- --------------------- ------------------------------------------------------------------------
34300 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34302 * @param {Object} config The config object
34304 register : function(config){
34305 var cs = config instanceof Array ? config : arguments;
34306 for(var i = 0, len = cs.length; i < len; i++) {
34308 var target = c.target;
34310 if(target instanceof Array){
34311 for(var j = 0, jlen = target.length; j < jlen; j++){
34312 tagEls[target[j]] = c;
34315 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34322 * Removes this quick tip from its element and destroys it.
34323 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34325 unregister : function(el){
34326 delete tagEls[Roo.id(el)];
34330 * Enable this quick tip.
34332 enable : function(){
34333 if(inited && disabled){
34335 if(locks.length < 1){
34342 * Disable this quick tip.
34344 disable : function(){
34346 clearTimeout(showProc);
34347 clearTimeout(hideProc);
34348 clearTimeout(dismissProc);
34356 * Returns true if the quick tip is enabled, else false.
34358 isEnabled : function(){
34364 namespace : "roo", // was ext?? this may break..
34365 alt_namespace : "ext",
34366 attribute : "qtip",
34376 // backwards compat
34377 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34379 * Ext JS Library 1.1.1
34380 * Copyright(c) 2006-2007, Ext JS, LLC.
34382 * Originally Released Under LGPL - original licence link has changed is not relivant.
34385 * <script type="text/javascript">
34390 * @class Roo.tree.TreePanel
34391 * @extends Roo.data.Tree
34392 * @cfg {Roo.tree.TreeNode} root The root node
34393 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34394 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34395 * @cfg {Boolean} enableDD true to enable drag and drop
34396 * @cfg {Boolean} enableDrag true to enable just drag
34397 * @cfg {Boolean} enableDrop true to enable just drop
34398 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34399 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34400 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34401 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34402 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34403 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34404 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34405 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34406 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34407 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34408 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34409 * @cfg {Roo.tree.TreeLoader} loader A TreeLoader for use with this TreePanel
34410 * @cfg {Roo.tree.TreeEditor} editor The TreeEditor to display when clicked.
34411 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34412 * @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>
34413 * @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>
34416 * @param {String/HTMLElement/Element} el The container element
34417 * @param {Object} config
34419 Roo.tree.TreePanel = function(el, config){
34421 var loader = false;
34423 root = config.root;
34424 delete config.root;
34426 if (config.loader) {
34427 loader = config.loader;
34428 delete config.loader;
34431 Roo.apply(this, config);
34432 Roo.tree.TreePanel.superclass.constructor.call(this);
34433 this.el = Roo.get(el);
34434 this.el.addClass('x-tree');
34435 //console.log(root);
34437 this.setRootNode( Roo.factory(root, Roo.tree));
34440 this.loader = Roo.factory(loader, Roo.tree);
34443 * Read-only. The id of the container element becomes this TreePanel's id.
34445 this.id = this.el.id;
34448 * @event beforeload
34449 * Fires before a node is loaded, return false to cancel
34450 * @param {Node} node The node being loaded
34452 "beforeload" : true,
34455 * Fires when a node is loaded
34456 * @param {Node} node The node that was loaded
34460 * @event textchange
34461 * Fires when the text for a node is changed
34462 * @param {Node} node The node
34463 * @param {String} text The new text
34464 * @param {String} oldText The old text
34466 "textchange" : true,
34468 * @event beforeexpand
34469 * Fires before a node is expanded, return false to cancel.
34470 * @param {Node} node The node
34471 * @param {Boolean} deep
34472 * @param {Boolean} anim
34474 "beforeexpand" : true,
34476 * @event beforecollapse
34477 * Fires before a node is collapsed, return false to cancel.
34478 * @param {Node} node The node
34479 * @param {Boolean} deep
34480 * @param {Boolean} anim
34482 "beforecollapse" : true,
34485 * Fires when a node is expanded
34486 * @param {Node} node The node
34490 * @event disabledchange
34491 * Fires when the disabled status of a node changes
34492 * @param {Node} node The node
34493 * @param {Boolean} disabled
34495 "disabledchange" : true,
34498 * Fires when a node is collapsed
34499 * @param {Node} node The node
34503 * @event beforeclick
34504 * Fires before click processing on a node. Return false to cancel the default action.
34505 * @param {Node} node The node
34506 * @param {Roo.EventObject} e The event object
34508 "beforeclick":true,
34510 * @event checkchange
34511 * Fires when a node with a checkbox's checked property changes
34512 * @param {Node} this This node
34513 * @param {Boolean} checked
34515 "checkchange":true,
34518 * Fires when a node is clicked
34519 * @param {Node} node The node
34520 * @param {Roo.EventObject} e The event object
34525 * Fires when a node is double clicked
34526 * @param {Node} node The node
34527 * @param {Roo.EventObject} e The event object
34531 * @event contextmenu
34532 * Fires when a node is right clicked
34533 * @param {Node} node The node
34534 * @param {Roo.EventObject} e The event object
34536 "contextmenu":true,
34538 * @event beforechildrenrendered
34539 * Fires right before the child nodes for a node are rendered
34540 * @param {Node} node The node
34542 "beforechildrenrendered":true,
34545 * Fires when a node starts being dragged
34546 * @param {Roo.tree.TreePanel} this
34547 * @param {Roo.tree.TreeNode} node
34548 * @param {event} e The raw browser event
34550 "startdrag" : true,
34553 * Fires when a drag operation is complete
34554 * @param {Roo.tree.TreePanel} this
34555 * @param {Roo.tree.TreeNode} node
34556 * @param {event} e The raw browser event
34561 * Fires when a dragged node is dropped on a valid DD target
34562 * @param {Roo.tree.TreePanel} this
34563 * @param {Roo.tree.TreeNode} node
34564 * @param {DD} dd The dd it was dropped on
34565 * @param {event} e The raw browser event
34569 * @event beforenodedrop
34570 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34571 * passed to handlers has the following properties:<br />
34572 * <ul style="padding:5px;padding-left:16px;">
34573 * <li>tree - The TreePanel</li>
34574 * <li>target - The node being targeted for the drop</li>
34575 * <li>data - The drag data from the drag source</li>
34576 * <li>point - The point of the drop - append, above or below</li>
34577 * <li>source - The drag source</li>
34578 * <li>rawEvent - Raw mouse event</li>
34579 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34580 * to be inserted by setting them on this object.</li>
34581 * <li>cancel - Set this to true to cancel the drop.</li>
34583 * @param {Object} dropEvent
34585 "beforenodedrop" : true,
34588 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34589 * passed to handlers has the following properties:<br />
34590 * <ul style="padding:5px;padding-left:16px;">
34591 * <li>tree - The TreePanel</li>
34592 * <li>target - The node being targeted for the drop</li>
34593 * <li>data - The drag data from the drag source</li>
34594 * <li>point - The point of the drop - append, above or below</li>
34595 * <li>source - The drag source</li>
34596 * <li>rawEvent - Raw mouse event</li>
34597 * <li>dropNode - Dropped node(s).</li>
34599 * @param {Object} dropEvent
34603 * @event nodedragover
34604 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34605 * passed to handlers has the following properties:<br />
34606 * <ul style="padding:5px;padding-left:16px;">
34607 * <li>tree - The TreePanel</li>
34608 * <li>target - The node being targeted for the drop</li>
34609 * <li>data - The drag data from the drag source</li>
34610 * <li>point - The point of the drop - append, above or below</li>
34611 * <li>source - The drag source</li>
34612 * <li>rawEvent - Raw mouse event</li>
34613 * <li>dropNode - Drop node(s) provided by the source.</li>
34614 * <li>cancel - Set this to true to signal drop not allowed.</li>
34616 * @param {Object} dragOverEvent
34618 "nodedragover" : true,
34620 * @event appendnode
34621 * Fires when append node to the tree
34622 * @param {Roo.tree.TreePanel} this
34623 * @param {Roo.tree.TreeNode} node
34624 * @param {Number} index The index of the newly appended node
34626 "appendnode" : true
34629 if(this.singleExpand){
34630 this.on("beforeexpand", this.restrictExpand, this);
34633 this.editor.tree = this;
34634 this.editor = Roo.factory(this.editor, Roo.tree);
34637 if (this.selModel) {
34638 this.selModel = Roo.factory(this.selModel, Roo.tree);
34642 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34643 rootVisible : true,
34644 animate: Roo.enableFx,
34647 hlDrop : Roo.enableFx,
34651 rendererTip: false,
34653 restrictExpand : function(node){
34654 var p = node.parentNode;
34656 if(p.expandedChild && p.expandedChild.parentNode == p){
34657 p.expandedChild.collapse();
34659 p.expandedChild = node;
34663 // private override
34664 setRootNode : function(node){
34665 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34666 if(!this.rootVisible){
34667 node.ui = new Roo.tree.RootTreeNodeUI(node);
34673 * Returns the container element for this TreePanel
34675 getEl : function(){
34680 * Returns the default TreeLoader for this TreePanel
34682 getLoader : function(){
34683 return this.loader;
34689 expandAll : function(){
34690 this.root.expand(true);
34694 * Collapse all nodes
34696 collapseAll : function(){
34697 this.root.collapse(true);
34701 * Returns the selection model used by this TreePanel
34703 getSelectionModel : function(){
34704 if(!this.selModel){
34705 this.selModel = new Roo.tree.DefaultSelectionModel();
34707 return this.selModel;
34711 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34712 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34713 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34716 getChecked : function(a, startNode){
34717 startNode = startNode || this.root;
34719 var f = function(){
34720 if(this.attributes.checked){
34721 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34724 startNode.cascade(f);
34729 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34730 * @param {String} path
34731 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34732 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34733 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34735 expandPath : function(path, attr, callback){
34736 attr = attr || "id";
34737 var keys = path.split(this.pathSeparator);
34738 var curNode = this.root;
34739 if(curNode.attributes[attr] != keys[1]){ // invalid root
34741 callback(false, null);
34746 var f = function(){
34747 if(++index == keys.length){
34749 callback(true, curNode);
34753 var c = curNode.findChild(attr, keys[index]);
34756 callback(false, curNode);
34761 c.expand(false, false, f);
34763 curNode.expand(false, false, f);
34767 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34768 * @param {String} path
34769 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34770 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34771 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34773 selectPath : function(path, attr, callback){
34774 attr = attr || "id";
34775 var keys = path.split(this.pathSeparator);
34776 var v = keys.pop();
34777 if(keys.length > 0){
34778 var f = function(success, node){
34779 if(success && node){
34780 var n = node.findChild(attr, v);
34786 }else if(callback){
34787 callback(false, n);
34791 callback(false, n);
34795 this.expandPath(keys.join(this.pathSeparator), attr, f);
34797 this.root.select();
34799 callback(true, this.root);
34804 getTreeEl : function(){
34809 * Trigger rendering of this TreePanel
34811 render : function(){
34812 if (this.innerCt) {
34813 return this; // stop it rendering more than once!!
34816 this.innerCt = this.el.createChild({tag:"ul",
34817 cls:"x-tree-root-ct " +
34818 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34820 if(this.containerScroll){
34821 Roo.dd.ScrollManager.register(this.el);
34823 if((this.enableDD || this.enableDrop) && !this.dropZone){
34825 * The dropZone used by this tree if drop is enabled
34826 * @type Roo.tree.TreeDropZone
34828 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34829 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34832 if((this.enableDD || this.enableDrag) && !this.dragZone){
34834 * The dragZone used by this tree if drag is enabled
34835 * @type Roo.tree.TreeDragZone
34837 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34838 ddGroup: this.ddGroup || "TreeDD",
34839 scroll: this.ddScroll
34842 this.getSelectionModel().init(this);
34844 Roo.log("ROOT not set in tree");
34847 this.root.render();
34848 if(!this.rootVisible){
34849 this.root.renderChildren();
34855 * Ext JS Library 1.1.1
34856 * Copyright(c) 2006-2007, Ext JS, LLC.
34858 * Originally Released Under LGPL - original licence link has changed is not relivant.
34861 * <script type="text/javascript">
34866 * @class Roo.tree.DefaultSelectionModel
34867 * @extends Roo.util.Observable
34868 * The default single selection for a TreePanel.
34869 * @param {Object} cfg Configuration
34871 Roo.tree.DefaultSelectionModel = function(cfg){
34872 this.selNode = null;
34878 * @event selectionchange
34879 * Fires when the selected node changes
34880 * @param {DefaultSelectionModel} this
34881 * @param {TreeNode} node the new selection
34883 "selectionchange" : true,
34886 * @event beforeselect
34887 * Fires before the selected node changes, return false to cancel the change
34888 * @param {DefaultSelectionModel} this
34889 * @param {TreeNode} node the new selection
34890 * @param {TreeNode} node the old selection
34892 "beforeselect" : true
34895 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34898 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34899 init : function(tree){
34901 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34902 tree.on("click", this.onNodeClick, this);
34905 onNodeClick : function(node, e){
34906 if (e.ctrlKey && this.selNode == node) {
34907 this.unselect(node);
34915 * @param {TreeNode} node The node to select
34916 * @return {TreeNode} The selected node
34918 select : function(node){
34919 var last = this.selNode;
34920 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34922 last.ui.onSelectedChange(false);
34924 this.selNode = node;
34925 node.ui.onSelectedChange(true);
34926 this.fireEvent("selectionchange", this, node, last);
34933 * @param {TreeNode} node The node to unselect
34935 unselect : function(node){
34936 if(this.selNode == node){
34937 this.clearSelections();
34942 * Clear all selections
34944 clearSelections : function(){
34945 var n = this.selNode;
34947 n.ui.onSelectedChange(false);
34948 this.selNode = null;
34949 this.fireEvent("selectionchange", this, null);
34955 * Get the selected node
34956 * @return {TreeNode} The selected node
34958 getSelectedNode : function(){
34959 return this.selNode;
34963 * Returns true if the node is selected
34964 * @param {TreeNode} node The node to check
34965 * @return {Boolean}
34967 isSelected : function(node){
34968 return this.selNode == node;
34972 * Selects the node above the selected node in the tree, intelligently walking the nodes
34973 * @return TreeNode The new selection
34975 selectPrevious : function(){
34976 var s = this.selNode || this.lastSelNode;
34980 var ps = s.previousSibling;
34982 if(!ps.isExpanded() || ps.childNodes.length < 1){
34983 return this.select(ps);
34985 var lc = ps.lastChild;
34986 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34989 return this.select(lc);
34991 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34992 return this.select(s.parentNode);
34998 * Selects the node above the selected node in the tree, intelligently walking the nodes
34999 * @return TreeNode The new selection
35001 selectNext : function(){
35002 var s = this.selNode || this.lastSelNode;
35006 if(s.firstChild && s.isExpanded()){
35007 return this.select(s.firstChild);
35008 }else if(s.nextSibling){
35009 return this.select(s.nextSibling);
35010 }else if(s.parentNode){
35012 s.parentNode.bubble(function(){
35013 if(this.nextSibling){
35014 newS = this.getOwnerTree().selModel.select(this.nextSibling);
35023 onKeyDown : function(e){
35024 var s = this.selNode || this.lastSelNode;
35025 // undesirable, but required
35030 var k = e.getKey();
35038 this.selectPrevious();
35041 e.preventDefault();
35042 if(s.hasChildNodes()){
35043 if(!s.isExpanded()){
35045 }else if(s.firstChild){
35046 this.select(s.firstChild, e);
35051 e.preventDefault();
35052 if(s.hasChildNodes() && s.isExpanded()){
35054 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
35055 this.select(s.parentNode, e);
35063 * @class Roo.tree.MultiSelectionModel
35064 * @extends Roo.util.Observable
35065 * Multi selection for a TreePanel.
35066 * @param {Object} cfg Configuration
35068 Roo.tree.MultiSelectionModel = function(){
35069 this.selNodes = [];
35073 * @event selectionchange
35074 * Fires when the selected nodes change
35075 * @param {MultiSelectionModel} this
35076 * @param {Array} nodes Array of the selected nodes
35078 "selectionchange" : true
35080 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
35084 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
35085 init : function(tree){
35087 tree.getTreeEl().on("keydown", this.onKeyDown, this);
35088 tree.on("click", this.onNodeClick, this);
35091 onNodeClick : function(node, e){
35092 this.select(node, e, e.ctrlKey);
35097 * @param {TreeNode} node The node to select
35098 * @param {EventObject} e (optional) An event associated with the selection
35099 * @param {Boolean} keepExisting True to retain existing selections
35100 * @return {TreeNode} The selected node
35102 select : function(node, e, keepExisting){
35103 if(keepExisting !== true){
35104 this.clearSelections(true);
35106 if(this.isSelected(node)){
35107 this.lastSelNode = node;
35110 this.selNodes.push(node);
35111 this.selMap[node.id] = node;
35112 this.lastSelNode = node;
35113 node.ui.onSelectedChange(true);
35114 this.fireEvent("selectionchange", this, this.selNodes);
35120 * @param {TreeNode} node The node to unselect
35122 unselect : function(node){
35123 if(this.selMap[node.id]){
35124 node.ui.onSelectedChange(false);
35125 var sn = this.selNodes;
35128 index = sn.indexOf(node);
35130 for(var i = 0, len = sn.length; i < len; i++){
35138 this.selNodes.splice(index, 1);
35140 delete this.selMap[node.id];
35141 this.fireEvent("selectionchange", this, this.selNodes);
35146 * Clear all selections
35148 clearSelections : function(suppressEvent){
35149 var sn = this.selNodes;
35151 for(var i = 0, len = sn.length; i < len; i++){
35152 sn[i].ui.onSelectedChange(false);
35154 this.selNodes = [];
35156 if(suppressEvent !== true){
35157 this.fireEvent("selectionchange", this, this.selNodes);
35163 * Returns true if the node is selected
35164 * @param {TreeNode} node The node to check
35165 * @return {Boolean}
35167 isSelected : function(node){
35168 return this.selMap[node.id] ? true : false;
35172 * Returns an array of the selected nodes
35175 getSelectedNodes : function(){
35176 return this.selNodes;
35179 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35181 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35183 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35186 * Ext JS Library 1.1.1
35187 * Copyright(c) 2006-2007, Ext JS, LLC.
35189 * Originally Released Under LGPL - original licence link has changed is not relivant.
35192 * <script type="text/javascript">
35196 * @class Roo.tree.TreeNode
35197 * @extends Roo.data.Node
35198 * @cfg {String} text The text for this node
35199 * @cfg {Boolean} expanded true to start the node expanded
35200 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35201 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35202 * @cfg {Boolean} disabled true to start the node disabled
35203 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35204 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35205 * @cfg {String} cls A css class to be added to the node
35206 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35207 * @cfg {String} href URL of the link used for the node (defaults to #)
35208 * @cfg {String} hrefTarget target frame for the link
35209 * @cfg {String} qtip An Ext QuickTip for the node
35210 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35211 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35212 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35213 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35214 * (defaults to undefined with no checkbox rendered)
35216 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35218 Roo.tree.TreeNode = function(attributes){
35219 attributes = attributes || {};
35220 if(typeof attributes == "string"){
35221 attributes = {text: attributes};
35223 this.childrenRendered = false;
35224 this.rendered = false;
35225 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35226 this.expanded = attributes.expanded === true;
35227 this.isTarget = attributes.isTarget !== false;
35228 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35229 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35232 * Read-only. The text for this node. To change it use setText().
35235 this.text = attributes.text;
35237 * True if this node is disabled.
35240 this.disabled = attributes.disabled === true;
35244 * @event textchange
35245 * Fires when the text for this node is changed
35246 * @param {Node} this This node
35247 * @param {String} text The new text
35248 * @param {String} oldText The old text
35250 "textchange" : true,
35252 * @event beforeexpand
35253 * Fires before this node is expanded, return false to cancel.
35254 * @param {Node} this This node
35255 * @param {Boolean} deep
35256 * @param {Boolean} anim
35258 "beforeexpand" : true,
35260 * @event beforecollapse
35261 * Fires before this node is collapsed, return false to cancel.
35262 * @param {Node} this This node
35263 * @param {Boolean} deep
35264 * @param {Boolean} anim
35266 "beforecollapse" : true,
35269 * Fires when this node is expanded
35270 * @param {Node} this This node
35274 * @event disabledchange
35275 * Fires when the disabled status of this node changes
35276 * @param {Node} this This node
35277 * @param {Boolean} disabled
35279 "disabledchange" : true,
35282 * Fires when this node is collapsed
35283 * @param {Node} this This node
35287 * @event beforeclick
35288 * Fires before click processing. Return false to cancel the default action.
35289 * @param {Node} this This node
35290 * @param {Roo.EventObject} e The event object
35292 "beforeclick":true,
35294 * @event checkchange
35295 * Fires when a node with a checkbox's checked property changes
35296 * @param {Node} this This node
35297 * @param {Boolean} checked
35299 "checkchange":true,
35302 * Fires when this node is clicked
35303 * @param {Node} this This node
35304 * @param {Roo.EventObject} e The event object
35309 * Fires when this node is double clicked
35310 * @param {Node} this This node
35311 * @param {Roo.EventObject} e The event object
35315 * @event contextmenu
35316 * Fires when this node is right clicked
35317 * @param {Node} this This node
35318 * @param {Roo.EventObject} e The event object
35320 "contextmenu":true,
35322 * @event beforechildrenrendered
35323 * Fires right before the child nodes for this node are rendered
35324 * @param {Node} this This node
35326 "beforechildrenrendered":true
35329 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35332 * Read-only. The UI for this node
35335 this.ui = new uiClass(this);
35337 // finally support items[]
35338 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35343 Roo.each(this.attributes.items, function(c) {
35344 this.appendChild(Roo.factory(c,Roo.Tree));
35346 delete this.attributes.items;
35351 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35352 preventHScroll: true,
35354 * Returns true if this node is expanded
35355 * @return {Boolean}
35357 isExpanded : function(){
35358 return this.expanded;
35362 * Returns the UI object for this node
35363 * @return {TreeNodeUI}
35365 getUI : function(){
35369 // private override
35370 setFirstChild : function(node){
35371 var of = this.firstChild;
35372 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35373 if(this.childrenRendered && of && node != of){
35374 of.renderIndent(true, true);
35377 this.renderIndent(true, true);
35381 // private override
35382 setLastChild : function(node){
35383 var ol = this.lastChild;
35384 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35385 if(this.childrenRendered && ol && node != ol){
35386 ol.renderIndent(true, true);
35389 this.renderIndent(true, true);
35393 // these methods are overridden to provide lazy rendering support
35394 // private override
35395 appendChild : function()
35397 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35398 if(node && this.childrenRendered){
35401 this.ui.updateExpandIcon();
35405 // private override
35406 removeChild : function(node){
35407 this.ownerTree.getSelectionModel().unselect(node);
35408 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35409 // if it's been rendered remove dom node
35410 if(this.childrenRendered){
35413 if(this.childNodes.length < 1){
35414 this.collapse(false, false);
35416 this.ui.updateExpandIcon();
35418 if(!this.firstChild) {
35419 this.childrenRendered = false;
35424 // private override
35425 insertBefore : function(node, refNode){
35426 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35427 if(newNode && refNode && this.childrenRendered){
35430 this.ui.updateExpandIcon();
35435 * Sets the text for this node
35436 * @param {String} text
35438 setText : function(text){
35439 var oldText = this.text;
35441 this.attributes.text = text;
35442 if(this.rendered){ // event without subscribing
35443 this.ui.onTextChange(this, text, oldText);
35445 this.fireEvent("textchange", this, text, oldText);
35449 * Triggers selection of this node
35451 select : function(){
35452 this.getOwnerTree().getSelectionModel().select(this);
35456 * Triggers deselection of this node
35458 unselect : function(){
35459 this.getOwnerTree().getSelectionModel().unselect(this);
35463 * Returns true if this node is selected
35464 * @return {Boolean}
35466 isSelected : function(){
35467 return this.getOwnerTree().getSelectionModel().isSelected(this);
35471 * Expand this node.
35472 * @param {Boolean} deep (optional) True to expand all children as well
35473 * @param {Boolean} anim (optional) false to cancel the default animation
35474 * @param {Function} callback (optional) A callback to be called when
35475 * expanding this node completes (does not wait for deep expand to complete).
35476 * Called with 1 parameter, this node.
35478 expand : function(deep, anim, callback){
35479 if(!this.expanded){
35480 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35483 if(!this.childrenRendered){
35484 this.renderChildren();
35486 this.expanded = true;
35488 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35489 this.ui.animExpand(function(){
35490 this.fireEvent("expand", this);
35491 if(typeof callback == "function"){
35495 this.expandChildNodes(true);
35497 }.createDelegate(this));
35501 this.fireEvent("expand", this);
35502 if(typeof callback == "function"){
35507 if(typeof callback == "function"){
35512 this.expandChildNodes(true);
35516 isHiddenRoot : function(){
35517 return this.isRoot && !this.getOwnerTree().rootVisible;
35521 * Collapse this node.
35522 * @param {Boolean} deep (optional) True to collapse all children as well
35523 * @param {Boolean} anim (optional) false to cancel the default animation
35525 collapse : function(deep, anim){
35526 if(this.expanded && !this.isHiddenRoot()){
35527 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35530 this.expanded = false;
35531 if((this.getOwnerTree().animate && anim !== false) || anim){
35532 this.ui.animCollapse(function(){
35533 this.fireEvent("collapse", this);
35535 this.collapseChildNodes(true);
35537 }.createDelegate(this));
35540 this.ui.collapse();
35541 this.fireEvent("collapse", this);
35545 var cs = this.childNodes;
35546 for(var i = 0, len = cs.length; i < len; i++) {
35547 cs[i].collapse(true, false);
35553 delayedExpand : function(delay){
35554 if(!this.expandProcId){
35555 this.expandProcId = this.expand.defer(delay, this);
35560 cancelExpand : function(){
35561 if(this.expandProcId){
35562 clearTimeout(this.expandProcId);
35564 this.expandProcId = false;
35568 * Toggles expanded/collapsed state of the node
35570 toggle : function(){
35579 * Ensures all parent nodes are expanded
35581 ensureVisible : function(callback){
35582 var tree = this.getOwnerTree();
35583 tree.expandPath(this.parentNode.getPath(), false, function(){
35584 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35585 Roo.callback(callback);
35586 }.createDelegate(this));
35590 * Expand all child nodes
35591 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35593 expandChildNodes : function(deep){
35594 var cs = this.childNodes;
35595 for(var i = 0, len = cs.length; i < len; i++) {
35596 cs[i].expand(deep);
35601 * Collapse all child nodes
35602 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35604 collapseChildNodes : function(deep){
35605 var cs = this.childNodes;
35606 for(var i = 0, len = cs.length; i < len; i++) {
35607 cs[i].collapse(deep);
35612 * Disables this node
35614 disable : function(){
35615 this.disabled = true;
35617 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35618 this.ui.onDisableChange(this, true);
35620 this.fireEvent("disabledchange", this, true);
35624 * Enables this node
35626 enable : function(){
35627 this.disabled = false;
35628 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35629 this.ui.onDisableChange(this, false);
35631 this.fireEvent("disabledchange", this, false);
35635 renderChildren : function(suppressEvent){
35636 if(suppressEvent !== false){
35637 this.fireEvent("beforechildrenrendered", this);
35639 var cs = this.childNodes;
35640 for(var i = 0, len = cs.length; i < len; i++){
35641 cs[i].render(true);
35643 this.childrenRendered = true;
35647 sort : function(fn, scope){
35648 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35649 if(this.childrenRendered){
35650 var cs = this.childNodes;
35651 for(var i = 0, len = cs.length; i < len; i++){
35652 cs[i].render(true);
35658 render : function(bulkRender){
35659 this.ui.render(bulkRender);
35660 if(!this.rendered){
35661 this.rendered = true;
35663 this.expanded = false;
35664 this.expand(false, false);
35670 renderIndent : function(deep, refresh){
35672 this.ui.childIndent = null;
35674 this.ui.renderIndent();
35675 if(deep === true && this.childrenRendered){
35676 var cs = this.childNodes;
35677 for(var i = 0, len = cs.length; i < len; i++){
35678 cs[i].renderIndent(true, refresh);
35684 * Ext JS Library 1.1.1
35685 * Copyright(c) 2006-2007, Ext JS, LLC.
35687 * Originally Released Under LGPL - original licence link has changed is not relivant.
35690 * <script type="text/javascript">
35694 * @class Roo.tree.AsyncTreeNode
35695 * @extends Roo.tree.TreeNode
35696 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35698 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35700 Roo.tree.AsyncTreeNode = function(config){
35701 this.loaded = false;
35702 this.loading = false;
35703 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35705 * @event beforeload
35706 * Fires before this node is loaded, return false to cancel
35707 * @param {Node} this This node
35709 this.addEvents({'beforeload':true, 'load': true});
35712 * Fires when this node is loaded
35713 * @param {Node} this This node
35716 * The loader used by this node (defaults to using the tree's defined loader)
35721 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35722 expand : function(deep, anim, callback){
35723 if(this.loading){ // if an async load is already running, waiting til it's done
35725 var f = function(){
35726 if(!this.loading){ // done loading
35727 clearInterval(timer);
35728 this.expand(deep, anim, callback);
35730 }.createDelegate(this);
35731 timer = setInterval(f, 200);
35735 if(this.fireEvent("beforeload", this) === false){
35738 this.loading = true;
35739 this.ui.beforeLoad(this);
35740 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35742 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35746 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35750 * Returns true if this node is currently loading
35751 * @return {Boolean}
35753 isLoading : function(){
35754 return this.loading;
35757 loadComplete : function(deep, anim, callback){
35758 this.loading = false;
35759 this.loaded = true;
35760 this.ui.afterLoad(this);
35761 this.fireEvent("load", this);
35762 this.expand(deep, anim, callback);
35766 * Returns true if this node has been loaded
35767 * @return {Boolean}
35769 isLoaded : function(){
35770 return this.loaded;
35773 hasChildNodes : function(){
35774 if(!this.isLeaf() && !this.loaded){
35777 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35782 * Trigger a reload for this node
35783 * @param {Function} callback
35785 reload : function(callback){
35786 this.collapse(false, false);
35787 while(this.firstChild){
35788 this.removeChild(this.firstChild);
35790 this.childrenRendered = false;
35791 this.loaded = false;
35792 if(this.isHiddenRoot()){
35793 this.expanded = false;
35795 this.expand(false, false, callback);
35799 * Ext JS Library 1.1.1
35800 * Copyright(c) 2006-2007, Ext JS, LLC.
35802 * Originally Released Under LGPL - original licence link has changed is not relivant.
35805 * <script type="text/javascript">
35809 * @class Roo.tree.TreeNodeUI
35811 * @param {Object} node The node to render
35812 * The TreeNode UI implementation is separate from the
35813 * tree implementation. Unless you are customizing the tree UI,
35814 * you should never have to use this directly.
35816 Roo.tree.TreeNodeUI = function(node){
35818 this.rendered = false;
35819 this.animating = false;
35820 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35823 Roo.tree.TreeNodeUI.prototype = {
35824 removeChild : function(node){
35826 this.ctNode.removeChild(node.ui.getEl());
35830 beforeLoad : function(){
35831 this.addClass("x-tree-node-loading");
35834 afterLoad : function(){
35835 this.removeClass("x-tree-node-loading");
35838 onTextChange : function(node, text, oldText){
35840 this.textNode.innerHTML = text;
35844 onDisableChange : function(node, state){
35845 this.disabled = state;
35847 this.addClass("x-tree-node-disabled");
35849 this.removeClass("x-tree-node-disabled");
35853 onSelectedChange : function(state){
35856 this.addClass("x-tree-selected");
35859 this.removeClass("x-tree-selected");
35863 onMove : function(tree, node, oldParent, newParent, index, refNode){
35864 this.childIndent = null;
35866 var targetNode = newParent.ui.getContainer();
35867 if(!targetNode){//target not rendered
35868 this.holder = document.createElement("div");
35869 this.holder.appendChild(this.wrap);
35872 var insertBefore = refNode ? refNode.ui.getEl() : null;
35874 targetNode.insertBefore(this.wrap, insertBefore);
35876 targetNode.appendChild(this.wrap);
35878 this.node.renderIndent(true);
35882 addClass : function(cls){
35884 Roo.fly(this.elNode).addClass(cls);
35888 removeClass : function(cls){
35890 Roo.fly(this.elNode).removeClass(cls);
35894 remove : function(){
35896 this.holder = document.createElement("div");
35897 this.holder.appendChild(this.wrap);
35901 fireEvent : function(){
35902 return this.node.fireEvent.apply(this.node, arguments);
35905 initEvents : function(){
35906 this.node.on("move", this.onMove, this);
35907 var E = Roo.EventManager;
35908 var a = this.anchor;
35910 var el = Roo.fly(a, '_treeui');
35912 if(Roo.isOpera){ // opera render bug ignores the CSS
35913 el.setStyle("text-decoration", "none");
35916 el.on("click", this.onClick, this);
35917 el.on("dblclick", this.onDblClick, this);
35920 Roo.EventManager.on(this.checkbox,
35921 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35924 el.on("contextmenu", this.onContextMenu, this);
35926 var icon = Roo.fly(this.iconNode);
35927 icon.on("click", this.onClick, this);
35928 icon.on("dblclick", this.onDblClick, this);
35929 icon.on("contextmenu", this.onContextMenu, this);
35930 E.on(this.ecNode, "click", this.ecClick, this, true);
35932 if(this.node.disabled){
35933 this.addClass("x-tree-node-disabled");
35935 if(this.node.hidden){
35936 this.addClass("x-tree-node-disabled");
35938 var ot = this.node.getOwnerTree();
35939 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35940 if(dd && (!this.node.isRoot || ot.rootVisible)){
35941 Roo.dd.Registry.register(this.elNode, {
35943 handles: this.getDDHandles(),
35949 getDDHandles : function(){
35950 return [this.iconNode, this.textNode];
35955 this.wrap.style.display = "none";
35961 this.wrap.style.display = "";
35965 onContextMenu : function(e){
35966 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35967 e.preventDefault();
35969 this.fireEvent("contextmenu", this.node, e);
35973 onClick : function(e){
35978 if(this.fireEvent("beforeclick", this.node, e) !== false){
35979 if(!this.disabled && this.node.attributes.href){
35980 this.fireEvent("click", this.node, e);
35983 e.preventDefault();
35988 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35989 this.node.toggle();
35992 this.fireEvent("click", this.node, e);
35998 onDblClick : function(e){
35999 e.preventDefault();
36004 this.toggleCheck();
36006 if(!this.animating && this.node.hasChildNodes()){
36007 this.node.toggle();
36009 this.fireEvent("dblclick", this.node, e);
36012 onCheckChange : function(){
36013 var checked = this.checkbox.checked;
36014 this.node.attributes.checked = checked;
36015 this.fireEvent('checkchange', this.node, checked);
36018 ecClick : function(e){
36019 if(!this.animating && this.node.hasChildNodes()){
36020 this.node.toggle();
36024 startDrop : function(){
36025 this.dropping = true;
36028 // delayed drop so the click event doesn't get fired on a drop
36029 endDrop : function(){
36030 setTimeout(function(){
36031 this.dropping = false;
36032 }.createDelegate(this), 50);
36035 expand : function(){
36036 this.updateExpandIcon();
36037 this.ctNode.style.display = "";
36040 focus : function(){
36041 if(!this.node.preventHScroll){
36042 try{this.anchor.focus();
36044 }else if(!Roo.isIE){
36046 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
36047 var l = noscroll.scrollLeft;
36048 this.anchor.focus();
36049 noscroll.scrollLeft = l;
36054 toggleCheck : function(value){
36055 var cb = this.checkbox;
36057 cb.checked = (value === undefined ? !cb.checked : value);
36063 this.anchor.blur();
36067 animExpand : function(callback){
36068 var ct = Roo.get(this.ctNode);
36070 if(!this.node.hasChildNodes()){
36071 this.updateExpandIcon();
36072 this.ctNode.style.display = "";
36073 Roo.callback(callback);
36076 this.animating = true;
36077 this.updateExpandIcon();
36080 callback : function(){
36081 this.animating = false;
36082 Roo.callback(callback);
36085 duration: this.node.ownerTree.duration || .25
36089 highlight : function(){
36090 var tree = this.node.getOwnerTree();
36091 Roo.fly(this.wrap).highlight(
36092 tree.hlColor || "C3DAF9",
36093 {endColor: tree.hlBaseColor}
36097 collapse : function(){
36098 this.updateExpandIcon();
36099 this.ctNode.style.display = "none";
36102 animCollapse : function(callback){
36103 var ct = Roo.get(this.ctNode);
36104 ct.enableDisplayMode('block');
36107 this.animating = true;
36108 this.updateExpandIcon();
36111 callback : function(){
36112 this.animating = false;
36113 Roo.callback(callback);
36116 duration: this.node.ownerTree.duration || .25
36120 getContainer : function(){
36121 return this.ctNode;
36124 getEl : function(){
36128 appendDDGhost : function(ghostNode){
36129 ghostNode.appendChild(this.elNode.cloneNode(true));
36132 getDDRepairXY : function(){
36133 return Roo.lib.Dom.getXY(this.iconNode);
36136 onRender : function(){
36140 render : function(bulkRender){
36141 var n = this.node, a = n.attributes;
36142 var targetNode = n.parentNode ?
36143 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
36145 if(!this.rendered){
36146 this.rendered = true;
36148 this.renderElements(n, a, targetNode, bulkRender);
36151 if(this.textNode.setAttributeNS){
36152 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
36154 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
36157 this.textNode.setAttribute("ext:qtip", a.qtip);
36159 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
36162 }else if(a.qtipCfg){
36163 a.qtipCfg.target = Roo.id(this.textNode);
36164 Roo.QuickTips.register(a.qtipCfg);
36167 if(!this.node.expanded){
36168 this.updateExpandIcon();
36171 if(bulkRender === true) {
36172 targetNode.appendChild(this.wrap);
36177 renderElements : function(n, a, targetNode, bulkRender)
36179 // add some indent caching, this helps performance when rendering a large tree
36180 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36181 var t = n.getOwnerTree();
36182 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36183 if (typeof(n.attributes.html) != 'undefined') {
36184 txt = n.attributes.html;
36186 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36187 var cb = typeof a.checked == 'boolean';
36188 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36189 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36190 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36191 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36192 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
36193 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
36194 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
36195 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
36196 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
36197 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36200 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36201 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36202 n.nextSibling.ui.getEl(), buf.join(""));
36204 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36207 this.elNode = this.wrap.childNodes[0];
36208 this.ctNode = this.wrap.childNodes[1];
36209 var cs = this.elNode.childNodes;
36210 this.indentNode = cs[0];
36211 this.ecNode = cs[1];
36212 this.iconNode = cs[2];
36215 this.checkbox = cs[3];
36218 this.anchor = cs[index];
36219 this.textNode = cs[index].firstChild;
36222 getAnchor : function(){
36223 return this.anchor;
36226 getTextEl : function(){
36227 return this.textNode;
36230 getIconEl : function(){
36231 return this.iconNode;
36234 isChecked : function(){
36235 return this.checkbox ? this.checkbox.checked : false;
36238 updateExpandIcon : function(){
36240 var n = this.node, c1, c2;
36241 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36242 var hasChild = n.hasChildNodes();
36246 c1 = "x-tree-node-collapsed";
36247 c2 = "x-tree-node-expanded";
36250 c1 = "x-tree-node-expanded";
36251 c2 = "x-tree-node-collapsed";
36254 this.removeClass("x-tree-node-leaf");
36255 this.wasLeaf = false;
36257 if(this.c1 != c1 || this.c2 != c2){
36258 Roo.fly(this.elNode).replaceClass(c1, c2);
36259 this.c1 = c1; this.c2 = c2;
36262 // this changes non-leafs into leafs if they have no children.
36263 // it's not very rational behaviour..
36265 if(!this.wasLeaf && this.node.leaf){
36266 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36269 this.wasLeaf = true;
36272 var ecc = "x-tree-ec-icon "+cls;
36273 if(this.ecc != ecc){
36274 this.ecNode.className = ecc;
36280 getChildIndent : function(){
36281 if(!this.childIndent){
36285 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36287 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36289 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36294 this.childIndent = buf.join("");
36296 return this.childIndent;
36299 renderIndent : function(){
36302 var p = this.node.parentNode;
36304 indent = p.ui.getChildIndent();
36306 if(this.indentMarkup != indent){ // don't rerender if not required
36307 this.indentNode.innerHTML = indent;
36308 this.indentMarkup = indent;
36310 this.updateExpandIcon();
36315 Roo.tree.RootTreeNodeUI = function(){
36316 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36318 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36319 render : function(){
36320 if(!this.rendered){
36321 var targetNode = this.node.ownerTree.innerCt.dom;
36322 this.node.expanded = true;
36323 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36324 this.wrap = this.ctNode = targetNode.firstChild;
36327 collapse : function(){
36329 expand : function(){
36333 * Ext JS Library 1.1.1
36334 * Copyright(c) 2006-2007, Ext JS, LLC.
36336 * Originally Released Under LGPL - original licence link has changed is not relivant.
36339 * <script type="text/javascript">
36342 * @class Roo.tree.TreeLoader
36343 * @extends Roo.util.Observable
36344 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36345 * nodes from a specified URL. The response must be a javascript Array definition
36346 * who's elements are node definition objects. eg:
36351 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36352 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36359 * The old style respose with just an array is still supported, but not recommended.
36362 * A server request is sent, and child nodes are loaded only when a node is expanded.
36363 * The loading node's id is passed to the server under the parameter name "node" to
36364 * enable the server to produce the correct child nodes.
36366 * To pass extra parameters, an event handler may be attached to the "beforeload"
36367 * event, and the parameters specified in the TreeLoader's baseParams property:
36369 myTreeLoader.on("beforeload", function(treeLoader, node) {
36370 this.baseParams.category = node.attributes.category;
36375 * This would pass an HTTP parameter called "category" to the server containing
36376 * the value of the Node's "category" attribute.
36378 * Creates a new Treeloader.
36379 * @param {Object} config A config object containing config properties.
36381 Roo.tree.TreeLoader = function(config){
36382 this.baseParams = {};
36383 this.requestMethod = "POST";
36384 Roo.apply(this, config);
36389 * @event beforeload
36390 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36391 * @param {Object} This TreeLoader object.
36392 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36393 * @param {Object} callback The callback function specified in the {@link #load} call.
36398 * Fires when the node has been successfuly loaded.
36399 * @param {Object} This TreeLoader object.
36400 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36401 * @param {Object} response The response object containing the data from the server.
36405 * @event loadexception
36406 * Fires if the network request failed.
36407 * @param {Object} This TreeLoader object.
36408 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36409 * @param {Object} response The response object containing the data from the server.
36411 loadexception : true,
36414 * Fires before a node is created, enabling you to return custom Node types
36415 * @param {Object} This TreeLoader object.
36416 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36421 Roo.tree.TreeLoader.superclass.constructor.call(this);
36424 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36426 * @cfg {String} dataUrl The URL from which to request a Json string which
36427 * specifies an array of node definition object representing the child nodes
36431 * @cfg {String} requestMethod either GET or POST
36432 * defaults to POST (due to BC)
36436 * @cfg {Object} baseParams (optional) An object containing properties which
36437 * specify HTTP parameters to be passed to each request for child nodes.
36440 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36441 * created by this loader. If the attributes sent by the server have an attribute in this object,
36442 * they take priority.
36445 * @cfg {Object} uiProviders (optional) An object containing properties which
36447 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36448 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36449 * <i>uiProvider</i> attribute of a returned child node is a string rather
36450 * than a reference to a TreeNodeUI implementation, this that string value
36451 * is used as a property name in the uiProviders object. You can define the provider named
36452 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36457 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36458 * child nodes before loading.
36460 clearOnLoad : true,
36463 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36464 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36465 * Grid query { data : [ .....] }
36470 * @cfg {String} queryParam (optional)
36471 * Name of the query as it will be passed on the querystring (defaults to 'node')
36472 * eg. the request will be ?node=[id]
36479 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36480 * This is called automatically when a node is expanded, but may be used to reload
36481 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36482 * @param {Roo.tree.TreeNode} node
36483 * @param {Function} callback
36485 load : function(node, callback){
36486 if(this.clearOnLoad){
36487 while(node.firstChild){
36488 node.removeChild(node.firstChild);
36491 if(node.attributes.children){ // preloaded json children
36492 var cs = node.attributes.children;
36493 for(var i = 0, len = cs.length; i < len; i++){
36494 node.appendChild(this.createNode(cs[i]));
36496 if(typeof callback == "function"){
36499 }else if(this.dataUrl){
36500 this.requestData(node, callback);
36504 getParams: function(node){
36505 var buf = [], bp = this.baseParams;
36506 for(var key in bp){
36507 if(typeof bp[key] != "function"){
36508 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36511 var n = this.queryParam === false ? 'node' : this.queryParam;
36512 buf.push(n + "=", encodeURIComponent(node.id));
36513 return buf.join("");
36516 requestData : function(node, callback){
36517 if(this.fireEvent("beforeload", this, node, callback) !== false){
36518 this.transId = Roo.Ajax.request({
36519 method:this.requestMethod,
36520 url: this.dataUrl||this.url,
36521 success: this.handleResponse,
36522 failure: this.handleFailure,
36524 argument: {callback: callback, node: node},
36525 params: this.getParams(node)
36528 // if the load is cancelled, make sure we notify
36529 // the node that we are done
36530 if(typeof callback == "function"){
36536 isLoading : function(){
36537 return this.transId ? true : false;
36540 abort : function(){
36541 if(this.isLoading()){
36542 Roo.Ajax.abort(this.transId);
36547 createNode : function(attr)
36549 // apply baseAttrs, nice idea Corey!
36550 if(this.baseAttrs){
36551 Roo.applyIf(attr, this.baseAttrs);
36553 if(this.applyLoader !== false){
36554 attr.loader = this;
36556 // uiProvider = depreciated..
36558 if(typeof(attr.uiProvider) == 'string'){
36559 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36560 /** eval:var:attr */ eval(attr.uiProvider);
36562 if(typeof(this.uiProviders['default']) != 'undefined') {
36563 attr.uiProvider = this.uiProviders['default'];
36566 this.fireEvent('create', this, attr);
36568 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36570 new Roo.tree.TreeNode(attr) :
36571 new Roo.tree.AsyncTreeNode(attr));
36574 processResponse : function(response, node, callback)
36576 var json = response.responseText;
36579 var o = Roo.decode(json);
36581 if (this.root === false && typeof(o.success) != undefined) {
36582 this.root = 'data'; // the default behaviour for list like data..
36585 if (this.root !== false && !o.success) {
36586 // it's a failure condition.
36587 var a = response.argument;
36588 this.fireEvent("loadexception", this, a.node, response);
36589 Roo.log("Load failed - should have a handler really");
36595 if (this.root !== false) {
36599 for(var i = 0, len = o.length; i < len; i++){
36600 var n = this.createNode(o[i]);
36602 node.appendChild(n);
36605 if(typeof callback == "function"){
36606 callback(this, node);
36609 this.handleFailure(response);
36613 handleResponse : function(response){
36614 this.transId = false;
36615 var a = response.argument;
36616 this.processResponse(response, a.node, a.callback);
36617 this.fireEvent("load", this, a.node, response);
36620 handleFailure : function(response)
36622 // should handle failure better..
36623 this.transId = false;
36624 var a = response.argument;
36625 this.fireEvent("loadexception", this, a.node, response);
36626 if(typeof a.callback == "function"){
36627 a.callback(this, a.node);
36632 * Ext JS Library 1.1.1
36633 * Copyright(c) 2006-2007, Ext JS, LLC.
36635 * Originally Released Under LGPL - original licence link has changed is not relivant.
36638 * <script type="text/javascript">
36642 * @class Roo.tree.TreeFilter
36643 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36644 * @param {TreePanel} tree
36645 * @param {Object} config (optional)
36647 Roo.tree.TreeFilter = function(tree, config){
36649 this.filtered = {};
36650 Roo.apply(this, config);
36653 Roo.tree.TreeFilter.prototype = {
36660 * Filter the data by a specific attribute.
36661 * @param {String/RegExp} value Either string that the attribute value
36662 * should start with or a RegExp to test against the attribute
36663 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36664 * @param {TreeNode} startNode (optional) The node to start the filter at.
36666 filter : function(value, attr, startNode){
36667 attr = attr || "text";
36669 if(typeof value == "string"){
36670 var vlen = value.length;
36671 // auto clear empty filter
36672 if(vlen == 0 && this.clearBlank){
36676 value = value.toLowerCase();
36678 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36680 }else if(value.exec){ // regex?
36682 return value.test(n.attributes[attr]);
36685 throw 'Illegal filter type, must be string or regex';
36687 this.filterBy(f, null, startNode);
36691 * Filter by a function. The passed function will be called with each
36692 * node in the tree (or from the startNode). If the function returns true, the node is kept
36693 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36694 * @param {Function} fn The filter function
36695 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36697 filterBy : function(fn, scope, startNode){
36698 startNode = startNode || this.tree.root;
36699 if(this.autoClear){
36702 var af = this.filtered, rv = this.reverse;
36703 var f = function(n){
36704 if(n == startNode){
36710 var m = fn.call(scope || n, n);
36718 startNode.cascade(f);
36721 if(typeof id != "function"){
36723 if(n && n.parentNode){
36724 n.parentNode.removeChild(n);
36732 * Clears the current filter. Note: with the "remove" option
36733 * set a filter cannot be cleared.
36735 clear : function(){
36737 var af = this.filtered;
36739 if(typeof id != "function"){
36746 this.filtered = {};
36751 * Ext JS Library 1.1.1
36752 * Copyright(c) 2006-2007, Ext JS, LLC.
36754 * Originally Released Under LGPL - original licence link has changed is not relivant.
36757 * <script type="text/javascript">
36762 * @class Roo.tree.TreeSorter
36763 * Provides sorting of nodes in a TreePanel
36765 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36766 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36767 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36768 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36769 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36770 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36772 * @param {TreePanel} tree
36773 * @param {Object} config
36775 Roo.tree.TreeSorter = function(tree, config){
36776 Roo.apply(this, config);
36777 tree.on("beforechildrenrendered", this.doSort, this);
36778 tree.on("append", this.updateSort, this);
36779 tree.on("insert", this.updateSort, this);
36781 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36782 var p = this.property || "text";
36783 var sortType = this.sortType;
36784 var fs = this.folderSort;
36785 var cs = this.caseSensitive === true;
36786 var leafAttr = this.leafAttr || 'leaf';
36788 this.sortFn = function(n1, n2){
36790 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36793 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36797 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36798 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36800 return dsc ? +1 : -1;
36802 return dsc ? -1 : +1;
36809 Roo.tree.TreeSorter.prototype = {
36810 doSort : function(node){
36811 node.sort(this.sortFn);
36814 compareNodes : function(n1, n2){
36815 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36818 updateSort : function(tree, node){
36819 if(node.childrenRendered){
36820 this.doSort.defer(1, this, [node]);
36825 * Ext JS Library 1.1.1
36826 * Copyright(c) 2006-2007, Ext JS, LLC.
36828 * Originally Released Under LGPL - original licence link has changed is not relivant.
36831 * <script type="text/javascript">
36834 if(Roo.dd.DropZone){
36836 Roo.tree.TreeDropZone = function(tree, config){
36837 this.allowParentInsert = false;
36838 this.allowContainerDrop = false;
36839 this.appendOnly = false;
36840 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36842 this.lastInsertClass = "x-tree-no-status";
36843 this.dragOverData = {};
36846 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36847 ddGroup : "TreeDD",
36850 expandDelay : 1000,
36852 expandNode : function(node){
36853 if(node.hasChildNodes() && !node.isExpanded()){
36854 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36858 queueExpand : function(node){
36859 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36862 cancelExpand : function(){
36863 if(this.expandProcId){
36864 clearTimeout(this.expandProcId);
36865 this.expandProcId = false;
36869 isValidDropPoint : function(n, pt, dd, e, data){
36870 if(!n || !data){ return false; }
36871 var targetNode = n.node;
36872 var dropNode = data.node;
36873 // default drop rules
36874 if(!(targetNode && targetNode.isTarget && pt)){
36877 if(pt == "append" && targetNode.allowChildren === false){
36880 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36883 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36886 // reuse the object
36887 var overEvent = this.dragOverData;
36888 overEvent.tree = this.tree;
36889 overEvent.target = targetNode;
36890 overEvent.data = data;
36891 overEvent.point = pt;
36892 overEvent.source = dd;
36893 overEvent.rawEvent = e;
36894 overEvent.dropNode = dropNode;
36895 overEvent.cancel = false;
36896 var result = this.tree.fireEvent("nodedragover", overEvent);
36897 return overEvent.cancel === false && result !== false;
36900 getDropPoint : function(e, n, dd)
36904 return tn.allowChildren !== false ? "append" : false; // always append for root
36906 var dragEl = n.ddel;
36907 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36908 var y = Roo.lib.Event.getPageY(e);
36909 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36911 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36912 var noAppend = tn.allowChildren === false;
36913 if(this.appendOnly || tn.parentNode.allowChildren === false){
36914 return noAppend ? false : "append";
36916 var noBelow = false;
36917 if(!this.allowParentInsert){
36918 noBelow = tn.hasChildNodes() && tn.isExpanded();
36920 var q = (b - t) / (noAppend ? 2 : 3);
36921 if(y >= t && y < (t + q)){
36923 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36930 onNodeEnter : function(n, dd, e, data)
36932 this.cancelExpand();
36935 onNodeOver : function(n, dd, e, data)
36938 var pt = this.getDropPoint(e, n, dd);
36941 // auto node expand check
36942 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36943 this.queueExpand(node);
36944 }else if(pt != "append"){
36945 this.cancelExpand();
36948 // set the insert point style on the target node
36949 var returnCls = this.dropNotAllowed;
36950 if(this.isValidDropPoint(n, pt, dd, e, data)){
36955 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36956 cls = "x-tree-drag-insert-above";
36957 }else if(pt == "below"){
36958 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36959 cls = "x-tree-drag-insert-below";
36961 returnCls = "x-tree-drop-ok-append";
36962 cls = "x-tree-drag-append";
36964 if(this.lastInsertClass != cls){
36965 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36966 this.lastInsertClass = cls;
36973 onNodeOut : function(n, dd, e, data){
36975 this.cancelExpand();
36976 this.removeDropIndicators(n);
36979 onNodeDrop : function(n, dd, e, data){
36980 var point = this.getDropPoint(e, n, dd);
36981 var targetNode = n.node;
36982 targetNode.ui.startDrop();
36983 if(!this.isValidDropPoint(n, point, dd, e, data)){
36984 targetNode.ui.endDrop();
36987 // first try to find the drop node
36988 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36991 target: targetNode,
36996 dropNode: dropNode,
36999 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
37000 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
37001 targetNode.ui.endDrop();
37004 // allow target changing
37005 targetNode = dropEvent.target;
37006 if(point == "append" && !targetNode.isExpanded()){
37007 targetNode.expand(false, null, function(){
37008 this.completeDrop(dropEvent);
37009 }.createDelegate(this));
37011 this.completeDrop(dropEvent);
37016 completeDrop : function(de){
37017 var ns = de.dropNode, p = de.point, t = de.target;
37018 if(!(ns instanceof Array)){
37022 for(var i = 0, len = ns.length; i < len; i++){
37025 t.parentNode.insertBefore(n, t);
37026 }else if(p == "below"){
37027 t.parentNode.insertBefore(n, t.nextSibling);
37033 if(this.tree.hlDrop){
37037 this.tree.fireEvent("nodedrop", de);
37040 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
37041 if(this.tree.hlDrop){
37042 dropNode.ui.focus();
37043 dropNode.ui.highlight();
37045 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
37048 getTree : function(){
37052 removeDropIndicators : function(n){
37055 Roo.fly(el).removeClass([
37056 "x-tree-drag-insert-above",
37057 "x-tree-drag-insert-below",
37058 "x-tree-drag-append"]);
37059 this.lastInsertClass = "_noclass";
37063 beforeDragDrop : function(target, e, id){
37064 this.cancelExpand();
37068 afterRepair : function(data){
37069 if(data && Roo.enableFx){
37070 data.node.ui.highlight();
37080 * Ext JS Library 1.1.1
37081 * Copyright(c) 2006-2007, Ext JS, LLC.
37083 * Originally Released Under LGPL - original licence link has changed is not relivant.
37086 * <script type="text/javascript">
37090 if(Roo.dd.DragZone){
37091 Roo.tree.TreeDragZone = function(tree, config){
37092 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
37096 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
37097 ddGroup : "TreeDD",
37099 onBeforeDrag : function(data, e){
37101 return n && n.draggable && !n.disabled;
37105 onInitDrag : function(e){
37106 var data = this.dragData;
37107 this.tree.getSelectionModel().select(data.node);
37108 this.proxy.update("");
37109 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
37110 this.tree.fireEvent("startdrag", this.tree, data.node, e);
37113 getRepairXY : function(e, data){
37114 return data.node.ui.getDDRepairXY();
37117 onEndDrag : function(data, e){
37118 this.tree.fireEvent("enddrag", this.tree, data.node, e);
37123 onValidDrop : function(dd, e, id){
37124 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
37128 beforeInvalidDrop : function(e, id){
37129 // this scrolls the original position back into view
37130 var sm = this.tree.getSelectionModel();
37131 sm.clearSelections();
37132 sm.select(this.dragData.node);
37137 * Ext JS Library 1.1.1
37138 * Copyright(c) 2006-2007, Ext JS, LLC.
37140 * Originally Released Under LGPL - original licence link has changed is not relivant.
37143 * <script type="text/javascript">
37146 * @class Roo.tree.TreeEditor
37147 * @extends Roo.Editor
37148 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
37149 * as the editor field.
37151 * @param {Object} config (used to be the tree panel.)
37152 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
37154 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
37155 * @cfg {Roo.form.TextField} field [required] The field configuration
37159 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
37162 if (oldconfig) { // old style..
37163 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
37166 tree = config.tree;
37167 config.field = config.field || {};
37168 config.field.xtype = 'TextField';
37169 field = Roo.factory(config.field, Roo.form);
37171 config = config || {};
37176 * @event beforenodeedit
37177 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37178 * false from the handler of this event.
37179 * @param {Editor} this
37180 * @param {Roo.tree.Node} node
37182 "beforenodeedit" : true
37186 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37190 tree.on('beforeclick', this.beforeNodeClick, this);
37191 tree.getTreeEl().on('mousedown', this.hide, this);
37192 this.on('complete', this.updateNode, this);
37193 this.on('beforestartedit', this.fitToTree, this);
37194 this.on('startedit', this.bindScroll, this, {delay:10});
37195 this.on('specialkey', this.onSpecialKey, this);
37198 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
37200 * @cfg {String} alignment
37201 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37207 * @cfg {Boolean} hideEl
37208 * True to hide the bound element while the editor is displayed (defaults to false)
37212 * @cfg {String} cls
37213 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37215 cls: "x-small-editor x-tree-editor",
37217 * @cfg {Boolean} shim
37218 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37224 * @cfg {Number} maxWidth
37225 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37226 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37227 * scroll and client offsets into account prior to each edit.
37234 fitToTree : function(ed, el){
37235 var td = this.tree.getTreeEl().dom, nd = el.dom;
37236 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37237 td.scrollLeft = nd.offsetLeft;
37241 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37242 this.setSize(w, '');
37244 return this.fireEvent('beforenodeedit', this, this.editNode);
37249 triggerEdit : function(node){
37250 this.completeEdit();
37251 this.editNode = node;
37252 this.startEdit(node.ui.textNode, node.text);
37256 bindScroll : function(){
37257 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37261 beforeNodeClick : function(node, e){
37262 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37263 this.lastClick = new Date();
37264 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37266 this.triggerEdit(node);
37273 updateNode : function(ed, value){
37274 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37275 this.editNode.setText(value);
37279 onHide : function(){
37280 Roo.tree.TreeEditor.superclass.onHide.call(this);
37282 this.editNode.ui.focus();
37287 onSpecialKey : function(field, e){
37288 var k = e.getKey();
37292 }else if(k == e.ENTER && !e.hasModifier()){
37294 this.completeEdit();
37297 });//<Script type="text/javascript">
37300 * Ext JS Library 1.1.1
37301 * Copyright(c) 2006-2007, Ext JS, LLC.
37303 * Originally Released Under LGPL - original licence link has changed is not relivant.
37306 * <script type="text/javascript">
37310 * Not documented??? - probably should be...
37313 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37314 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37316 renderElements : function(n, a, targetNode, bulkRender){
37317 //consel.log("renderElements?");
37318 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37320 var t = n.getOwnerTree();
37321 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37323 var cols = t.columns;
37324 var bw = t.borderWidth;
37326 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37327 var cb = typeof a.checked == "boolean";
37328 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37329 var colcls = 'x-t-' + tid + '-c0';
37331 '<li class="x-tree-node">',
37334 '<div class="x-tree-node-el ', a.cls,'">',
37336 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37339 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37340 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37341 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37342 (a.icon ? ' x-tree-node-inline-icon' : ''),
37343 (a.iconCls ? ' '+a.iconCls : ''),
37344 '" unselectable="on" />',
37345 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37346 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37348 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37349 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37350 '<span unselectable="on" qtip="' + tx + '">',
37354 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37355 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37357 for(var i = 1, len = cols.length; i < len; i++){
37359 colcls = 'x-t-' + tid + '-c' +i;
37360 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37361 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37362 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37368 '<div class="x-clear"></div></div>',
37369 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37372 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37373 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37374 n.nextSibling.ui.getEl(), buf.join(""));
37376 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37378 var el = this.wrap.firstChild;
37380 this.elNode = el.firstChild;
37381 this.ranchor = el.childNodes[1];
37382 this.ctNode = this.wrap.childNodes[1];
37383 var cs = el.firstChild.childNodes;
37384 this.indentNode = cs[0];
37385 this.ecNode = cs[1];
37386 this.iconNode = cs[2];
37389 this.checkbox = cs[3];
37392 this.anchor = cs[index];
37394 this.textNode = cs[index].firstChild;
37396 //el.on("click", this.onClick, this);
37397 //el.on("dblclick", this.onDblClick, this);
37400 // console.log(this);
37402 initEvents : function(){
37403 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37406 var a = this.ranchor;
37408 var el = Roo.get(a);
37410 if(Roo.isOpera){ // opera render bug ignores the CSS
37411 el.setStyle("text-decoration", "none");
37414 el.on("click", this.onClick, this);
37415 el.on("dblclick", this.onDblClick, this);
37416 el.on("contextmenu", this.onContextMenu, this);
37420 /*onSelectedChange : function(state){
37423 this.addClass("x-tree-selected");
37426 this.removeClass("x-tree-selected");
37429 addClass : function(cls){
37431 Roo.fly(this.elRow).addClass(cls);
37437 removeClass : function(cls){
37439 Roo.fly(this.elRow).removeClass(cls);
37445 });//<Script type="text/javascript">
37449 * Ext JS Library 1.1.1
37450 * Copyright(c) 2006-2007, Ext JS, LLC.
37452 * Originally Released Under LGPL - original licence link has changed is not relivant.
37455 * <script type="text/javascript">
37460 * @class Roo.tree.ColumnTree
37461 * @extends Roo.tree.TreePanel
37462 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37463 * @cfg {int} borderWidth compined right/left border allowance
37465 * @param {String/HTMLElement/Element} el The container element
37466 * @param {Object} config
37468 Roo.tree.ColumnTree = function(el, config)
37470 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37474 * Fire this event on a container when it resizes
37475 * @param {int} w Width
37476 * @param {int} h Height
37480 this.on('resize', this.onResize, this);
37483 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37487 borderWidth: Roo.isBorderBox ? 0 : 2,
37490 render : function(){
37491 // add the header.....
37493 Roo.tree.ColumnTree.superclass.render.apply(this);
37495 this.el.addClass('x-column-tree');
37497 this.headers = this.el.createChild(
37498 {cls:'x-tree-headers'},this.innerCt.dom);
37500 var cols = this.columns, c;
37501 var totalWidth = 0;
37503 var len = cols.length;
37504 for(var i = 0; i < len; i++){
37506 totalWidth += c.width;
37507 this.headEls.push(this.headers.createChild({
37508 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37510 cls:'x-tree-hd-text',
37513 style:'width:'+(c.width-this.borderWidth)+'px;'
37516 this.headers.createChild({cls:'x-clear'});
37517 // prevent floats from wrapping when clipped
37518 this.headers.setWidth(totalWidth);
37519 //this.innerCt.setWidth(totalWidth);
37520 this.innerCt.setStyle({ overflow: 'auto' });
37521 this.onResize(this.width, this.height);
37525 onResize : function(w,h)
37530 this.innerCt.setWidth(this.width);
37531 this.innerCt.setHeight(this.height-20);
37534 var cols = this.columns, c;
37535 var totalWidth = 0;
37537 var len = cols.length;
37538 for(var i = 0; i < len; i++){
37540 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37541 // it's the expander..
37542 expEl = this.headEls[i];
37545 totalWidth += c.width;
37549 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37551 this.headers.setWidth(w-20);
37560 * Ext JS Library 1.1.1
37561 * Copyright(c) 2006-2007, Ext JS, LLC.
37563 * Originally Released Under LGPL - original licence link has changed is not relivant.
37566 * <script type="text/javascript">
37570 * @class Roo.menu.Menu
37571 * @extends Roo.util.Observable
37572 * @children Roo.menu.BaseItem
37573 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37574 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37576 * Creates a new Menu
37577 * @param {Object} config Configuration options
37579 Roo.menu.Menu = function(config){
37581 Roo.menu.Menu.superclass.constructor.call(this, config);
37583 this.id = this.id || Roo.id();
37586 * @event beforeshow
37587 * Fires before this menu is displayed
37588 * @param {Roo.menu.Menu} this
37592 * @event beforehide
37593 * Fires before this menu is hidden
37594 * @param {Roo.menu.Menu} this
37599 * Fires after this menu is displayed
37600 * @param {Roo.menu.Menu} this
37605 * Fires after this menu is hidden
37606 * @param {Roo.menu.Menu} this
37611 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37612 * @param {Roo.menu.Menu} this
37613 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37614 * @param {Roo.EventObject} e
37619 * Fires when the mouse is hovering over this menu
37620 * @param {Roo.menu.Menu} this
37621 * @param {Roo.EventObject} e
37622 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37627 * Fires when the mouse exits this menu
37628 * @param {Roo.menu.Menu} this
37629 * @param {Roo.EventObject} e
37630 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37635 * Fires when a menu item contained in this menu is clicked
37636 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37637 * @param {Roo.EventObject} e
37641 if (this.registerMenu) {
37642 Roo.menu.MenuMgr.register(this);
37645 var mis = this.items;
37646 this.items = new Roo.util.MixedCollection();
37648 this.add.apply(this, mis);
37652 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37654 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37658 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37659 * for bottom-right shadow (defaults to "sides")
37663 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37664 * this menu (defaults to "tl-tr?")
37666 subMenuAlign : "tl-tr?",
37668 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37669 * relative to its element of origin (defaults to "tl-bl?")
37671 defaultAlign : "tl-bl?",
37673 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37675 allowOtherMenus : false,
37677 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37679 registerMenu : true,
37684 render : function(){
37688 var el = this.el = new Roo.Layer({
37690 shadow:this.shadow,
37692 parentEl: this.parentEl || document.body,
37696 this.keyNav = new Roo.menu.MenuNav(this);
37699 el.addClass("x-menu-plain");
37702 el.addClass(this.cls);
37704 // generic focus element
37705 this.focusEl = el.createChild({
37706 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37708 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37709 //disabling touch- as it's causing issues ..
37710 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37711 ul.on('click' , this.onClick, this);
37714 ul.on("mouseover", this.onMouseOver, this);
37715 ul.on("mouseout", this.onMouseOut, this);
37716 this.items.each(function(item){
37721 var li = document.createElement("li");
37722 li.className = "x-menu-list-item";
37723 ul.dom.appendChild(li);
37724 item.render(li, this);
37731 autoWidth : function(){
37732 var el = this.el, ul = this.ul;
37736 var w = this.width;
37739 }else if(Roo.isIE){
37740 el.setWidth(this.minWidth);
37741 var t = el.dom.offsetWidth; // force recalc
37742 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37747 delayAutoWidth : function(){
37750 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37752 this.awTask.delay(20);
37757 findTargetItem : function(e){
37758 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37759 if(t && t.menuItemId){
37760 return this.items.get(t.menuItemId);
37765 onClick : function(e){
37766 Roo.log("menu.onClick");
37767 var t = this.findTargetItem(e);
37772 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37773 if(t == this.activeItem && t.shouldDeactivate(e)){
37774 this.activeItem.deactivate();
37775 delete this.activeItem;
37779 this.setActiveItem(t, true);
37787 this.fireEvent("click", this, t, e);
37791 setActiveItem : function(item, autoExpand){
37792 if(item != this.activeItem){
37793 if(this.activeItem){
37794 this.activeItem.deactivate();
37796 this.activeItem = item;
37797 item.activate(autoExpand);
37798 }else if(autoExpand){
37804 tryActivate : function(start, step){
37805 var items = this.items;
37806 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37807 var item = items.get(i);
37808 if(!item.disabled && item.canActivate){
37809 this.setActiveItem(item, false);
37817 onMouseOver : function(e){
37819 if(t = this.findTargetItem(e)){
37820 if(t.canActivate && !t.disabled){
37821 this.setActiveItem(t, true);
37824 this.fireEvent("mouseover", this, e, t);
37828 onMouseOut : function(e){
37830 if(t = this.findTargetItem(e)){
37831 if(t == this.activeItem && t.shouldDeactivate(e)){
37832 this.activeItem.deactivate();
37833 delete this.activeItem;
37836 this.fireEvent("mouseout", this, e, t);
37840 * Read-only. Returns true if the menu is currently displayed, else false.
37843 isVisible : function(){
37844 return this.el && !this.hidden;
37848 * Displays this menu relative to another element
37849 * @param {String/HTMLElement/Roo.Element} element The element to align to
37850 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37851 * the element (defaults to this.defaultAlign)
37852 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37854 show : function(el, pos, parentMenu){
37855 this.parentMenu = parentMenu;
37859 this.fireEvent("beforeshow", this);
37860 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37864 * Displays this menu at a specific xy position
37865 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37866 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37868 showAt : function(xy, parentMenu, /* private: */_e){
37869 this.parentMenu = parentMenu;
37874 this.fireEvent("beforeshow", this);
37875 xy = this.el.adjustForConstraints(xy);
37879 this.hidden = false;
37881 this.fireEvent("show", this);
37884 focus : function(){
37886 this.doFocus.defer(50, this);
37890 doFocus : function(){
37892 this.focusEl.focus();
37897 * Hides this menu and optionally all parent menus
37898 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37900 hide : function(deep){
37901 if(this.el && this.isVisible()){
37902 this.fireEvent("beforehide", this);
37903 if(this.activeItem){
37904 this.activeItem.deactivate();
37905 this.activeItem = null;
37908 this.hidden = true;
37909 this.fireEvent("hide", this);
37911 if(deep === true && this.parentMenu){
37912 this.parentMenu.hide(true);
37917 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37918 * Any of the following are valid:
37920 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37921 * <li>An HTMLElement object which will be converted to a menu item</li>
37922 * <li>A menu item config object that will be created as a new menu item</li>
37923 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37924 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37929 var menu = new Roo.menu.Menu();
37931 // Create a menu item to add by reference
37932 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37934 // Add a bunch of items at once using different methods.
37935 // Only the last item added will be returned.
37936 var item = menu.add(
37937 menuItem, // add existing item by ref
37938 'Dynamic Item', // new TextItem
37939 '-', // new separator
37940 { text: 'Config Item' } // new item by config
37943 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37944 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37947 var a = arguments, l = a.length, item;
37948 for(var i = 0; i < l; i++){
37950 if ((typeof(el) == "object") && el.xtype && el.xns) {
37951 el = Roo.factory(el, Roo.menu);
37954 if(el.render){ // some kind of Item
37955 item = this.addItem(el);
37956 }else if(typeof el == "string"){ // string
37957 if(el == "separator" || el == "-"){
37958 item = this.addSeparator();
37960 item = this.addText(el);
37962 }else if(el.tagName || el.el){ // element
37963 item = this.addElement(el);
37964 }else if(typeof el == "object"){ // must be menu item config?
37965 item = this.addMenuItem(el);
37972 * Returns this menu's underlying {@link Roo.Element} object
37973 * @return {Roo.Element} The element
37975 getEl : function(){
37983 * Adds a separator bar to the menu
37984 * @return {Roo.menu.Item} The menu item that was added
37986 addSeparator : function(){
37987 return this.addItem(new Roo.menu.Separator());
37991 * Adds an {@link Roo.Element} object to the menu
37992 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37993 * @return {Roo.menu.Item} The menu item that was added
37995 addElement : function(el){
37996 return this.addItem(new Roo.menu.BaseItem(el));
38000 * Adds an existing object based on {@link Roo.menu.Item} to the menu
38001 * @param {Roo.menu.Item} item The menu item to add
38002 * @return {Roo.menu.Item} The menu item that was added
38004 addItem : function(item){
38005 this.items.add(item);
38007 var li = document.createElement("li");
38008 li.className = "x-menu-list-item";
38009 this.ul.dom.appendChild(li);
38010 item.render(li, this);
38011 this.delayAutoWidth();
38017 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
38018 * @param {Object} config A MenuItem config object
38019 * @return {Roo.menu.Item} The menu item that was added
38021 addMenuItem : function(config){
38022 if(!(config instanceof Roo.menu.Item)){
38023 if(typeof config.checked == "boolean"){ // must be check menu item config?
38024 config = new Roo.menu.CheckItem(config);
38026 config = new Roo.menu.Item(config);
38029 return this.addItem(config);
38033 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
38034 * @param {String} text The text to display in the menu item
38035 * @return {Roo.menu.Item} The menu item that was added
38037 addText : function(text){
38038 return this.addItem(new Roo.menu.TextItem({ text : text }));
38042 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
38043 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
38044 * @param {Roo.menu.Item} item The menu item to add
38045 * @return {Roo.menu.Item} The menu item that was added
38047 insert : function(index, item){
38048 this.items.insert(index, item);
38050 var li = document.createElement("li");
38051 li.className = "x-menu-list-item";
38052 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
38053 item.render(li, this);
38054 this.delayAutoWidth();
38060 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
38061 * @param {Roo.menu.Item} item The menu item to remove
38063 remove : function(item){
38064 this.items.removeKey(item.id);
38069 * Removes and destroys all items in the menu
38071 removeAll : function(){
38073 while(f = this.items.first()){
38079 // MenuNav is a private utility class used internally by the Menu
38080 Roo.menu.MenuNav = function(menu){
38081 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
38082 this.scope = this.menu = menu;
38085 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
38086 doRelay : function(e, h){
38087 var k = e.getKey();
38088 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
38089 this.menu.tryActivate(0, 1);
38092 return h.call(this.scope || this, e, this.menu);
38095 up : function(e, m){
38096 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
38097 m.tryActivate(m.items.length-1, -1);
38101 down : function(e, m){
38102 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
38103 m.tryActivate(0, 1);
38107 right : function(e, m){
38109 m.activeItem.expandMenu(true);
38113 left : function(e, m){
38115 if(m.parentMenu && m.parentMenu.activeItem){
38116 m.parentMenu.activeItem.activate();
38120 enter : function(e, m){
38122 e.stopPropagation();
38123 m.activeItem.onClick(e);
38124 m.fireEvent("click", this, m.activeItem);
38130 * Ext JS Library 1.1.1
38131 * Copyright(c) 2006-2007, Ext JS, LLC.
38133 * Originally Released Under LGPL - original licence link has changed is not relivant.
38136 * <script type="text/javascript">
38140 * @class Roo.menu.MenuMgr
38141 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
38144 Roo.menu.MenuMgr = function(){
38145 var menus, active, groups = {}, attached = false, lastShow = new Date();
38147 // private - called when first menu is created
38150 active = new Roo.util.MixedCollection();
38151 Roo.get(document).addKeyListener(27, function(){
38152 if(active.length > 0){
38159 function hideAll(){
38160 if(active && active.length > 0){
38161 var c = active.clone();
38162 c.each(function(m){
38169 function onHide(m){
38171 if(active.length < 1){
38172 Roo.get(document).un("mousedown", onMouseDown);
38178 function onShow(m){
38179 var last = active.last();
38180 lastShow = new Date();
38183 Roo.get(document).on("mousedown", onMouseDown);
38187 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38188 m.parentMenu.activeChild = m;
38189 }else if(last && last.isVisible()){
38190 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
38195 function onBeforeHide(m){
38197 m.activeChild.hide();
38199 if(m.autoHideTimer){
38200 clearTimeout(m.autoHideTimer);
38201 delete m.autoHideTimer;
38206 function onBeforeShow(m){
38207 var pm = m.parentMenu;
38208 if(!pm && !m.allowOtherMenus){
38210 }else if(pm && pm.activeChild && active != m){
38211 pm.activeChild.hide();
38216 function onMouseDown(e){
38217 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38223 function onBeforeCheck(mi, state){
38225 var g = groups[mi.group];
38226 for(var i = 0, l = g.length; i < l; i++){
38228 g[i].setChecked(false);
38237 * Hides all menus that are currently visible
38239 hideAll : function(){
38244 register : function(menu){
38248 menus[menu.id] = menu;
38249 menu.on("beforehide", onBeforeHide);
38250 menu.on("hide", onHide);
38251 menu.on("beforeshow", onBeforeShow);
38252 menu.on("show", onShow);
38253 var g = menu.group;
38254 if(g && menu.events["checkchange"]){
38258 groups[g].push(menu);
38259 menu.on("checkchange", onCheck);
38264 * Returns a {@link Roo.menu.Menu} object
38265 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38266 * be used to generate and return a new Menu instance.
38268 get : function(menu){
38269 if(typeof menu == "string"){ // menu id
38270 return menus[menu];
38271 }else if(menu.events){ // menu instance
38273 }else if(typeof menu.length == 'number'){ // array of menu items?
38274 return new Roo.menu.Menu({items:menu});
38275 }else{ // otherwise, must be a config
38276 return new Roo.menu.Menu(menu);
38281 unregister : function(menu){
38282 delete menus[menu.id];
38283 menu.un("beforehide", onBeforeHide);
38284 menu.un("hide", onHide);
38285 menu.un("beforeshow", onBeforeShow);
38286 menu.un("show", onShow);
38287 var g = menu.group;
38288 if(g && menu.events["checkchange"]){
38289 groups[g].remove(menu);
38290 menu.un("checkchange", onCheck);
38295 registerCheckable : function(menuItem){
38296 var g = menuItem.group;
38301 groups[g].push(menuItem);
38302 menuItem.on("beforecheckchange", onBeforeCheck);
38307 unregisterCheckable : function(menuItem){
38308 var g = menuItem.group;
38310 groups[g].remove(menuItem);
38311 menuItem.un("beforecheckchange", onBeforeCheck);
38317 * Ext JS Library 1.1.1
38318 * Copyright(c) 2006-2007, Ext JS, LLC.
38320 * Originally Released Under LGPL - original licence link has changed is not relivant.
38323 * <script type="text/javascript">
38328 * @class Roo.menu.BaseItem
38329 * @extends Roo.Component
38331 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38332 * management and base configuration options shared by all menu components.
38334 * Creates a new BaseItem
38335 * @param {Object} config Configuration options
38337 Roo.menu.BaseItem = function(config){
38338 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38343 * Fires when this item is clicked
38344 * @param {Roo.menu.BaseItem} this
38345 * @param {Roo.EventObject} e
38350 * Fires when this item is activated
38351 * @param {Roo.menu.BaseItem} this
38355 * @event deactivate
38356 * Fires when this item is deactivated
38357 * @param {Roo.menu.BaseItem} this
38363 this.on("click", this.handler, this.scope, true);
38367 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38369 * @cfg {Function} handler
38370 * A function that will handle the click event of this menu item (defaults to undefined)
38373 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38375 canActivate : false,
38378 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38383 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38385 activeClass : "x-menu-item-active",
38387 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38389 hideOnClick : true,
38391 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38396 ctype: "Roo.menu.BaseItem",
38399 actionMode : "container",
38402 render : function(container, parentMenu){
38403 this.parentMenu = parentMenu;
38404 Roo.menu.BaseItem.superclass.render.call(this, container);
38405 this.container.menuItemId = this.id;
38409 onRender : function(container, position){
38410 this.el = Roo.get(this.el);
38411 container.dom.appendChild(this.el.dom);
38415 onClick : function(e){
38416 if(!this.disabled && this.fireEvent("click", this, e) !== false
38417 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38418 this.handleClick(e);
38425 activate : function(){
38429 var li = this.container;
38430 li.addClass(this.activeClass);
38431 this.region = li.getRegion().adjust(2, 2, -2, -2);
38432 this.fireEvent("activate", this);
38437 deactivate : function(){
38438 this.container.removeClass(this.activeClass);
38439 this.fireEvent("deactivate", this);
38443 shouldDeactivate : function(e){
38444 return !this.region || !this.region.contains(e.getPoint());
38448 handleClick : function(e){
38449 if(this.hideOnClick){
38450 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38455 expandMenu : function(autoActivate){
38460 hideMenu : function(){
38465 * Ext JS Library 1.1.1
38466 * Copyright(c) 2006-2007, Ext JS, LLC.
38468 * Originally Released Under LGPL - original licence link has changed is not relivant.
38471 * <script type="text/javascript">
38475 * @class Roo.menu.Adapter
38476 * @extends Roo.menu.BaseItem
38478 * 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.
38479 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38481 * Creates a new Adapter
38482 * @param {Object} config Configuration options
38484 Roo.menu.Adapter = function(component, config){
38485 Roo.menu.Adapter.superclass.constructor.call(this, config);
38486 this.component = component;
38488 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38490 canActivate : true,
38493 onRender : function(container, position){
38494 this.component.render(container);
38495 this.el = this.component.getEl();
38499 activate : function(){
38503 this.component.focus();
38504 this.fireEvent("activate", this);
38509 deactivate : function(){
38510 this.fireEvent("deactivate", this);
38514 disable : function(){
38515 this.component.disable();
38516 Roo.menu.Adapter.superclass.disable.call(this);
38520 enable : function(){
38521 this.component.enable();
38522 Roo.menu.Adapter.superclass.enable.call(this);
38526 * Ext JS Library 1.1.1
38527 * Copyright(c) 2006-2007, Ext JS, LLC.
38529 * Originally Released Under LGPL - original licence link has changed is not relivant.
38532 * <script type="text/javascript">
38536 * @class Roo.menu.TextItem
38537 * @extends Roo.menu.BaseItem
38538 * Adds a static text string to a menu, usually used as either a heading or group separator.
38539 * Note: old style constructor with text is still supported.
38542 * Creates a new TextItem
38543 * @param {Object} cfg Configuration
38545 Roo.menu.TextItem = function(cfg){
38546 if (typeof(cfg) == 'string') {
38549 Roo.apply(this,cfg);
38552 Roo.menu.TextItem.superclass.constructor.call(this);
38555 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38557 * @cfg {String} text Text to show on item.
38562 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38564 hideOnClick : false,
38566 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38568 itemCls : "x-menu-text",
38571 onRender : function(){
38572 var s = document.createElement("span");
38573 s.className = this.itemCls;
38574 s.innerHTML = this.text;
38576 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38580 * Ext JS Library 1.1.1
38581 * Copyright(c) 2006-2007, Ext JS, LLC.
38583 * Originally Released Under LGPL - original licence link has changed is not relivant.
38586 * <script type="text/javascript">
38590 * @class Roo.menu.Separator
38591 * @extends Roo.menu.BaseItem
38592 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38593 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38595 * @param {Object} config Configuration options
38597 Roo.menu.Separator = function(config){
38598 Roo.menu.Separator.superclass.constructor.call(this, config);
38601 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38603 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38605 itemCls : "x-menu-sep",
38607 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38609 hideOnClick : false,
38612 onRender : function(li){
38613 var s = document.createElement("span");
38614 s.className = this.itemCls;
38615 s.innerHTML = " ";
38617 li.addClass("x-menu-sep-li");
38618 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38622 * Ext JS Library 1.1.1
38623 * Copyright(c) 2006-2007, Ext JS, LLC.
38625 * Originally Released Under LGPL - original licence link has changed is not relivant.
38628 * <script type="text/javascript">
38631 * @class Roo.menu.Item
38632 * @extends Roo.menu.BaseItem
38633 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38634 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38635 * activation and click handling.
38637 * Creates a new Item
38638 * @param {Object} config Configuration options
38640 Roo.menu.Item = function(config){
38641 Roo.menu.Item.superclass.constructor.call(this, config);
38643 this.menu = Roo.menu.MenuMgr.get(this.menu);
38646 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38648 * @cfg {Roo.menu.Menu} menu
38652 * @cfg {String} text
38653 * The text to show on the menu item.
38657 * @cfg {String} HTML to render in menu
38658 * The text to show on the menu item (HTML version).
38662 * @cfg {String} icon
38663 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38667 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38669 itemCls : "x-menu-item",
38671 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38673 canActivate : true,
38675 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38678 // doc'd in BaseItem
38682 ctype: "Roo.menu.Item",
38685 onRender : function(container, position){
38686 var el = document.createElement("a");
38687 el.hideFocus = true;
38688 el.unselectable = "on";
38689 el.href = this.href || "#";
38690 if(this.hrefTarget){
38691 el.target = this.hrefTarget;
38693 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38695 var html = this.html.length ? this.html : String.format('{0}',this.text);
38697 el.innerHTML = String.format(
38698 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38699 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38701 Roo.menu.Item.superclass.onRender.call(this, container, position);
38705 * Sets the text to display in this menu item
38706 * @param {String} text The text to display
38707 * @param {Boolean} isHTML true to indicate text is pure html.
38709 setText : function(text, isHTML){
38717 var html = this.html.length ? this.html : String.format('{0}',this.text);
38719 this.el.update(String.format(
38720 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38721 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38722 this.parentMenu.autoWidth();
38727 handleClick : function(e){
38728 if(!this.href){ // if no link defined, stop the event automatically
38731 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38735 activate : function(autoExpand){
38736 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38746 shouldDeactivate : function(e){
38747 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38748 if(this.menu && this.menu.isVisible()){
38749 return !this.menu.getEl().getRegion().contains(e.getPoint());
38757 deactivate : function(){
38758 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38763 expandMenu : function(autoActivate){
38764 if(!this.disabled && this.menu){
38765 clearTimeout(this.hideTimer);
38766 delete this.hideTimer;
38767 if(!this.menu.isVisible() && !this.showTimer){
38768 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38769 }else if (this.menu.isVisible() && autoActivate){
38770 this.menu.tryActivate(0, 1);
38776 deferExpand : function(autoActivate){
38777 delete this.showTimer;
38778 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38780 this.menu.tryActivate(0, 1);
38785 hideMenu : function(){
38786 clearTimeout(this.showTimer);
38787 delete this.showTimer;
38788 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38789 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38794 deferHide : function(){
38795 delete this.hideTimer;
38800 * Ext JS Library 1.1.1
38801 * Copyright(c) 2006-2007, Ext JS, LLC.
38803 * Originally Released Under LGPL - original licence link has changed is not relivant.
38806 * <script type="text/javascript">
38810 * @class Roo.menu.CheckItem
38811 * @extends Roo.menu.Item
38812 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38814 * Creates a new CheckItem
38815 * @param {Object} config Configuration options
38817 Roo.menu.CheckItem = function(config){
38818 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38821 * @event beforecheckchange
38822 * Fires before the checked value is set, providing an opportunity to cancel if needed
38823 * @param {Roo.menu.CheckItem} this
38824 * @param {Boolean} checked The new checked value that will be set
38826 "beforecheckchange" : true,
38828 * @event checkchange
38829 * Fires after the checked value has been set
38830 * @param {Roo.menu.CheckItem} this
38831 * @param {Boolean} checked The checked value that was set
38833 "checkchange" : true
38835 if(this.checkHandler){
38836 this.on('checkchange', this.checkHandler, this.scope);
38839 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38841 * @cfg {String} group
38842 * All check items with the same group name will automatically be grouped into a single-select
38843 * radio button group (defaults to '')
38846 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38848 itemCls : "x-menu-item x-menu-check-item",
38850 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38852 groupClass : "x-menu-group-item",
38855 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38856 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38857 * initialized with checked = true will be rendered as checked.
38862 ctype: "Roo.menu.CheckItem",
38865 onRender : function(c){
38866 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38868 this.el.addClass(this.groupClass);
38870 Roo.menu.MenuMgr.registerCheckable(this);
38872 this.checked = false;
38873 this.setChecked(true, true);
38878 destroy : function(){
38880 Roo.menu.MenuMgr.unregisterCheckable(this);
38882 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38886 * Set the checked state of this item
38887 * @param {Boolean} checked The new checked value
38888 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38890 setChecked : function(state, suppressEvent){
38891 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38892 if(this.container){
38893 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38895 this.checked = state;
38896 if(suppressEvent !== true){
38897 this.fireEvent("checkchange", this, state);
38903 handleClick : function(e){
38904 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38905 this.setChecked(!this.checked);
38907 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38911 * Ext JS Library 1.1.1
38912 * Copyright(c) 2006-2007, Ext JS, LLC.
38914 * Originally Released Under LGPL - original licence link has changed is not relivant.
38917 * <script type="text/javascript">
38921 * @class Roo.menu.DateItem
38922 * @extends Roo.menu.Adapter
38923 * A menu item that wraps the {@link Roo.DatPicker} component.
38925 * Creates a new DateItem
38926 * @param {Object} config Configuration options
38928 Roo.menu.DateItem = function(config){
38929 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38930 /** The Roo.DatePicker object @type Roo.DatePicker */
38931 this.picker = this.component;
38932 this.addEvents({select: true});
38934 this.picker.on("render", function(picker){
38935 picker.getEl().swallowEvent("click");
38936 picker.container.addClass("x-menu-date-item");
38939 this.picker.on("select", this.onSelect, this);
38942 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38944 onSelect : function(picker, date){
38945 this.fireEvent("select", this, date, picker);
38946 Roo.menu.DateItem.superclass.handleClick.call(this);
38950 * Ext JS Library 1.1.1
38951 * Copyright(c) 2006-2007, Ext JS, LLC.
38953 * Originally Released Under LGPL - original licence link has changed is not relivant.
38956 * <script type="text/javascript">
38960 * @class Roo.menu.ColorItem
38961 * @extends Roo.menu.Adapter
38962 * A menu item that wraps the {@link Roo.ColorPalette} component.
38964 * Creates a new ColorItem
38965 * @param {Object} config Configuration options
38967 Roo.menu.ColorItem = function(config){
38968 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38969 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38970 this.palette = this.component;
38971 this.relayEvents(this.palette, ["select"]);
38972 if(this.selectHandler){
38973 this.on('select', this.selectHandler, this.scope);
38976 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38978 * Ext JS Library 1.1.1
38979 * Copyright(c) 2006-2007, Ext JS, LLC.
38981 * Originally Released Under LGPL - original licence link has changed is not relivant.
38984 * <script type="text/javascript">
38989 * @class Roo.menu.DateMenu
38990 * @extends Roo.menu.Menu
38991 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38993 * Creates a new DateMenu
38994 * @param {Object} config Configuration options
38996 Roo.menu.DateMenu = function(config){
38997 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38999 var di = new Roo.menu.DateItem(config);
39002 * The {@link Roo.DatePicker} instance for this DateMenu
39005 this.picker = di.picker;
39008 * @param {DatePicker} picker
39009 * @param {Date} date
39011 this.relayEvents(di, ["select"]);
39012 this.on('beforeshow', function(){
39014 this.picker.hideMonthPicker(false);
39018 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
39022 * Ext JS Library 1.1.1
39023 * Copyright(c) 2006-2007, Ext JS, LLC.
39025 * Originally Released Under LGPL - original licence link has changed is not relivant.
39028 * <script type="text/javascript">
39033 * @class Roo.menu.ColorMenu
39034 * @extends Roo.menu.Menu
39035 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
39037 * Creates a new ColorMenu
39038 * @param {Object} config Configuration options
39040 Roo.menu.ColorMenu = function(config){
39041 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
39043 var ci = new Roo.menu.ColorItem(config);
39046 * The {@link Roo.ColorPalette} instance for this ColorMenu
39047 * @type ColorPalette
39049 this.palette = ci.palette;
39052 * @param {ColorPalette} palette
39053 * @param {String} color
39055 this.relayEvents(ci, ["select"]);
39057 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
39059 * Ext JS Library 1.1.1
39060 * Copyright(c) 2006-2007, Ext JS, LLC.
39062 * Originally Released Under LGPL - original licence link has changed is not relivant.
39065 * <script type="text/javascript">
39069 * @class Roo.form.TextItem
39070 * @extends Roo.BoxComponent
39071 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39073 * Creates a new TextItem
39074 * @param {Object} config Configuration options
39076 Roo.form.TextItem = function(config){
39077 Roo.form.TextItem.superclass.constructor.call(this, config);
39080 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
39083 * @cfg {String} tag the tag for this item (default div)
39087 * @cfg {String} html the content for this item
39091 getAutoCreate : function()
39104 onRender : function(ct, position)
39106 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
39109 var cfg = this.getAutoCreate();
39111 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39113 if (!cfg.name.length) {
39116 this.el = ct.createChild(cfg, position);
39121 * @param {String} html update the Contents of the element.
39123 setHTML : function(html)
39125 this.fieldEl.dom.innerHTML = html;
39130 * Ext JS Library 1.1.1
39131 * Copyright(c) 2006-2007, Ext JS, LLC.
39133 * Originally Released Under LGPL - original licence link has changed is not relivant.
39136 * <script type="text/javascript">
39140 * @class Roo.form.Field
39141 * @extends Roo.BoxComponent
39142 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39144 * Creates a new Field
39145 * @param {Object} config Configuration options
39147 Roo.form.Field = function(config){
39148 Roo.form.Field.superclass.constructor.call(this, config);
39151 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
39153 * @cfg {String} fieldLabel Label to use when rendering a form.
39156 * @cfg {String} qtip Mouse over tip
39160 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
39162 invalidClass : "x-form-invalid",
39164 * @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")
39166 invalidText : "The value in this field is invalid",
39168 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
39170 focusClass : "x-form-focus",
39172 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
39173 automatic validation (defaults to "keyup").
39175 validationEvent : "keyup",
39177 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
39179 validateOnBlur : true,
39181 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39183 validationDelay : 250,
39185 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39186 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39188 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39190 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39192 fieldClass : "x-form-field",
39194 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
39197 ----------- ----------------------------------------------------------------------
39198 qtip Display a quick tip when the user hovers over the field
39199 title Display a default browser title attribute popup
39200 under Add a block div beneath the field containing the error text
39201 side Add an error icon to the right of the field with a popup on hover
39202 [element id] Add the error text directly to the innerHTML of the specified element
39205 msgTarget : 'qtip',
39207 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39212 * @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.
39217 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39222 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39224 inputType : undefined,
39227 * @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).
39229 tabIndex : undefined,
39232 isFormField : true,
39237 * @property {Roo.Element} fieldEl
39238 * Element Containing the rendered Field (with label etc.)
39241 * @cfg {Mixed} value A value to initialize this field with.
39246 * @cfg {String} name The field's HTML name attribute.
39249 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39252 loadedValue : false,
39256 initComponent : function(){
39257 Roo.form.Field.superclass.initComponent.call(this);
39261 * Fires when this field receives input focus.
39262 * @param {Roo.form.Field} this
39267 * Fires when this field loses input focus.
39268 * @param {Roo.form.Field} this
39272 * @event specialkey
39273 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39274 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39275 * @param {Roo.form.Field} this
39276 * @param {Roo.EventObject} e The event object
39281 * Fires just before the field blurs if the field value has changed.
39282 * @param {Roo.form.Field} this
39283 * @param {Mixed} newValue The new value
39284 * @param {Mixed} oldValue The original value
39289 * Fires after the field has been marked as invalid.
39290 * @param {Roo.form.Field} this
39291 * @param {String} msg The validation message
39296 * Fires after the field has been validated with no errors.
39297 * @param {Roo.form.Field} this
39302 * Fires after the key up
39303 * @param {Roo.form.Field} this
39304 * @param {Roo.EventObject} e The event Object
39311 * Returns the name attribute of the field if available
39312 * @return {String} name The field name
39314 getName: function(){
39315 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39319 onRender : function(ct, position){
39320 Roo.form.Field.superclass.onRender.call(this, ct, position);
39322 var cfg = this.getAutoCreate();
39324 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39326 if (!cfg.name.length) {
39329 if(this.inputType){
39330 cfg.type = this.inputType;
39332 this.el = ct.createChild(cfg, position);
39334 var type = this.el.dom.type;
39336 if(type == 'password'){
39339 this.el.addClass('x-form-'+type);
39342 this.el.dom.readOnly = true;
39344 if(this.tabIndex !== undefined){
39345 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39348 this.el.addClass([this.fieldClass, this.cls]);
39353 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39354 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39355 * @return {Roo.form.Field} this
39357 applyTo : function(target){
39358 this.allowDomMove = false;
39359 this.el = Roo.get(target);
39360 this.render(this.el.dom.parentNode);
39365 initValue : function(){
39366 if(this.value !== undefined){
39367 this.setValue(this.value);
39368 }else if(this.el.dom.value.length > 0){
39369 this.setValue(this.el.dom.value);
39374 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39375 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39377 isDirty : function() {
39378 if(this.disabled) {
39381 return String(this.getValue()) !== String(this.originalValue);
39385 * stores the current value in loadedValue
39387 resetHasChanged : function()
39389 this.loadedValue = String(this.getValue());
39392 * checks the current value against the 'loaded' value.
39393 * Note - will return false if 'resetHasChanged' has not been called first.
39395 hasChanged : function()
39397 if(this.disabled || this.readOnly) {
39400 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39406 afterRender : function(){
39407 Roo.form.Field.superclass.afterRender.call(this);
39412 fireKey : function(e){
39413 //Roo.log('field ' + e.getKey());
39414 if(e.isNavKeyPress()){
39415 this.fireEvent("specialkey", this, e);
39420 * Resets the current field value to the originally loaded value and clears any validation messages
39422 reset : function(){
39423 this.setValue(this.resetValue);
39424 this.originalValue = this.getValue();
39425 this.clearInvalid();
39429 initEvents : function(){
39430 // safari killled keypress - so keydown is now used..
39431 this.el.on("keydown" , this.fireKey, this);
39432 this.el.on("focus", this.onFocus, this);
39433 this.el.on("blur", this.onBlur, this);
39434 this.el.relayEvent('keyup', this);
39436 // reference to original value for reset
39437 this.originalValue = this.getValue();
39438 this.resetValue = this.getValue();
39442 onFocus : function(){
39443 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39444 this.el.addClass(this.focusClass);
39446 if(!this.hasFocus){
39447 this.hasFocus = true;
39448 this.startValue = this.getValue();
39449 this.fireEvent("focus", this);
39453 beforeBlur : Roo.emptyFn,
39456 onBlur : function(){
39458 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39459 this.el.removeClass(this.focusClass);
39461 this.hasFocus = false;
39462 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39465 var v = this.getValue();
39466 if(String(v) !== String(this.startValue)){
39467 this.fireEvent('change', this, v, this.startValue);
39469 this.fireEvent("blur", this);
39473 * Returns whether or not the field value is currently valid
39474 * @param {Boolean} preventMark True to disable marking the field invalid
39475 * @return {Boolean} True if the value is valid, else false
39477 isValid : function(preventMark){
39481 var restore = this.preventMark;
39482 this.preventMark = preventMark === true;
39483 var v = this.validateValue(this.processValue(this.getRawValue()));
39484 this.preventMark = restore;
39489 * Validates the field value
39490 * @return {Boolean} True if the value is valid, else false
39492 validate : function(){
39493 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39494 this.clearInvalid();
39500 processValue : function(value){
39505 // Subclasses should provide the validation implementation by overriding this
39506 validateValue : function(value){
39511 * Mark this field as invalid
39512 * @param {String} msg The validation message
39514 markInvalid : function(msg){
39515 if(!this.rendered || this.preventMark){ // not rendered
39519 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39521 obj.el.addClass(this.invalidClass);
39522 msg = msg || this.invalidText;
39523 switch(this.msgTarget){
39525 obj.el.dom.qtip = msg;
39526 obj.el.dom.qclass = 'x-form-invalid-tip';
39527 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39528 Roo.QuickTips.enable();
39532 this.el.dom.title = msg;
39536 var elp = this.el.findParent('.x-form-element', 5, true);
39537 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39538 this.errorEl.setWidth(elp.getWidth(true)-20);
39540 this.errorEl.update(msg);
39541 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39544 if(!this.errorIcon){
39545 var elp = this.el.findParent('.x-form-element', 5, true);
39546 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39548 this.alignErrorIcon();
39549 this.errorIcon.dom.qtip = msg;
39550 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39551 this.errorIcon.show();
39552 this.on('resize', this.alignErrorIcon, this);
39555 var t = Roo.getDom(this.msgTarget);
39557 t.style.display = this.msgDisplay;
39560 this.fireEvent('invalid', this, msg);
39564 alignErrorIcon : function(){
39565 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39569 * Clear any invalid styles/messages for this field
39571 clearInvalid : function(){
39572 if(!this.rendered || this.preventMark){ // not rendered
39575 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39577 obj.el.removeClass(this.invalidClass);
39578 switch(this.msgTarget){
39580 obj.el.dom.qtip = '';
39583 this.el.dom.title = '';
39587 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39591 if(this.errorIcon){
39592 this.errorIcon.dom.qtip = '';
39593 this.errorIcon.hide();
39594 this.un('resize', this.alignErrorIcon, this);
39598 var t = Roo.getDom(this.msgTarget);
39600 t.style.display = 'none';
39603 this.fireEvent('valid', this);
39607 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39608 * @return {Mixed} value The field value
39610 getRawValue : function(){
39611 var v = this.el.getValue();
39617 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39618 * @return {Mixed} value The field value
39620 getValue : function(){
39621 var v = this.el.getValue();
39627 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39628 * @param {Mixed} value The value to set
39630 setRawValue : function(v){
39631 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39635 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39636 * @param {Mixed} value The value to set
39638 setValue : function(v){
39641 this.el.dom.value = (v === null || v === undefined ? '' : v);
39646 adjustSize : function(w, h){
39647 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39648 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39652 adjustWidth : function(tag, w){
39653 tag = tag.toLowerCase();
39654 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39655 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39656 if(tag == 'input'){
39659 if(tag == 'textarea'){
39662 }else if(Roo.isOpera){
39663 if(tag == 'input'){
39666 if(tag == 'textarea'){
39676 // anything other than normal should be considered experimental
39677 Roo.form.Field.msgFx = {
39679 show: function(msgEl, f){
39680 msgEl.setDisplayed('block');
39683 hide : function(msgEl, f){
39684 msgEl.setDisplayed(false).update('');
39689 show: function(msgEl, f){
39690 msgEl.slideIn('t', {stopFx:true});
39693 hide : function(msgEl, f){
39694 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39699 show: function(msgEl, f){
39700 msgEl.fixDisplay();
39701 msgEl.alignTo(f.el, 'tl-tr');
39702 msgEl.slideIn('l', {stopFx:true});
39705 hide : function(msgEl, f){
39706 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39711 * Ext JS Library 1.1.1
39712 * Copyright(c) 2006-2007, Ext JS, LLC.
39714 * Originally Released Under LGPL - original licence link has changed is not relivant.
39717 * <script type="text/javascript">
39722 * @class Roo.form.TextField
39723 * @extends Roo.form.Field
39724 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39725 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39727 * Creates a new TextField
39728 * @param {Object} config Configuration options
39730 Roo.form.TextField = function(config){
39731 Roo.form.TextField.superclass.constructor.call(this, config);
39735 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39736 * according to the default logic, but this event provides a hook for the developer to apply additional
39737 * logic at runtime to resize the field if needed.
39738 * @param {Roo.form.Field} this This text field
39739 * @param {Number} width The new field width
39745 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39747 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39751 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39755 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39759 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39763 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39767 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39769 disableKeyFilter : false,
39771 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39775 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39779 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39781 maxLength : Number.MAX_VALUE,
39783 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39785 minLengthText : "The minimum length for this field is {0}",
39787 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39789 maxLengthText : "The maximum length for this field is {0}",
39791 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39793 selectOnFocus : false,
39795 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39797 allowLeadingSpace : false,
39799 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39801 blankText : "This field is required",
39803 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39804 * If available, this function will be called only after the basic validators all return true, and will be passed the
39805 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39809 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39810 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39811 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39815 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39819 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39825 initEvents : function()
39827 if (this.emptyText) {
39828 this.el.attr('placeholder', this.emptyText);
39831 Roo.form.TextField.superclass.initEvents.call(this);
39832 if(this.validationEvent == 'keyup'){
39833 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39834 this.el.on('keyup', this.filterValidation, this);
39836 else if(this.validationEvent !== false){
39837 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39840 if(this.selectOnFocus){
39841 this.on("focus", this.preFocus, this);
39843 if (!this.allowLeadingSpace) {
39844 this.on('blur', this.cleanLeadingSpace, this);
39847 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39848 this.el.on("keypress", this.filterKeys, this);
39851 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39852 this.el.on("click", this.autoSize, this);
39854 if(this.el.is('input[type=password]') && Roo.isSafari){
39855 this.el.on('keydown', this.SafariOnKeyDown, this);
39859 processValue : function(value){
39860 if(this.stripCharsRe){
39861 var newValue = value.replace(this.stripCharsRe, '');
39862 if(newValue !== value){
39863 this.setRawValue(newValue);
39870 filterValidation : function(e){
39871 if(!e.isNavKeyPress()){
39872 this.validationTask.delay(this.validationDelay);
39877 onKeyUp : function(e){
39878 if(!e.isNavKeyPress()){
39882 // private - clean the leading white space
39883 cleanLeadingSpace : function(e)
39885 if ( this.inputType == 'file') {
39889 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39892 * Resets the current field value to the originally-loaded value and clears any validation messages.
39895 reset : function(){
39896 Roo.form.TextField.superclass.reset.call(this);
39900 preFocus : function(){
39902 if(this.selectOnFocus){
39903 this.el.dom.select();
39909 filterKeys : function(e){
39910 var k = e.getKey();
39911 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39914 var c = e.getCharCode(), cc = String.fromCharCode(c);
39915 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39918 if(!this.maskRe.test(cc)){
39923 setValue : function(v){
39925 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39931 * Validates a value according to the field's validation rules and marks the field as invalid
39932 * if the validation fails
39933 * @param {Mixed} value The value to validate
39934 * @return {Boolean} True if the value is valid, else false
39936 validateValue : function(value){
39937 if(value.length < 1) { // if it's blank
39938 if(this.allowBlank){
39939 this.clearInvalid();
39942 this.markInvalid(this.blankText);
39946 if(value.length < this.minLength){
39947 this.markInvalid(String.format(this.minLengthText, this.minLength));
39950 if(value.length > this.maxLength){
39951 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39955 var vt = Roo.form.VTypes;
39956 if(!vt[this.vtype](value, this)){
39957 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39961 if(typeof this.validator == "function"){
39962 var msg = this.validator(value);
39964 this.markInvalid(msg);
39968 if(this.regex && !this.regex.test(value)){
39969 this.markInvalid(this.regexText);
39976 * Selects text in this field
39977 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39978 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39980 selectText : function(start, end){
39981 var v = this.getRawValue();
39983 start = start === undefined ? 0 : start;
39984 end = end === undefined ? v.length : end;
39985 var d = this.el.dom;
39986 if(d.setSelectionRange){
39987 d.setSelectionRange(start, end);
39988 }else if(d.createTextRange){
39989 var range = d.createTextRange();
39990 range.moveStart("character", start);
39991 range.moveEnd("character", v.length-end);
39998 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39999 * This only takes effect if grow = true, and fires the autosize event.
40001 autoSize : function(){
40002 if(!this.grow || !this.rendered){
40006 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
40009 var v = el.dom.value;
40010 var d = document.createElement('div');
40011 d.appendChild(document.createTextNode(v));
40015 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
40016 this.el.setWidth(w);
40017 this.fireEvent("autosize", this, w);
40021 SafariOnKeyDown : function(event)
40023 // this is a workaround for a password hang bug on chrome/ webkit.
40025 var isSelectAll = false;
40027 if(this.el.dom.selectionEnd > 0){
40028 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
40030 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
40031 event.preventDefault();
40036 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
40038 event.preventDefault();
40039 // this is very hacky as keydown always get's upper case.
40041 var cc = String.fromCharCode(event.getCharCode());
40044 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
40052 * Ext JS Library 1.1.1
40053 * Copyright(c) 2006-2007, Ext JS, LLC.
40055 * Originally Released Under LGPL - original licence link has changed is not relivant.
40058 * <script type="text/javascript">
40062 * @class Roo.form.Hidden
40063 * @extends Roo.form.TextField
40064 * Simple Hidden element used on forms
40066 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
40069 * Creates a new Hidden form element.
40070 * @param {Object} config Configuration options
40075 // easy hidden field...
40076 Roo.form.Hidden = function(config){
40077 Roo.form.Hidden.superclass.constructor.call(this, config);
40080 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
40082 inputType: 'hidden',
40085 labelSeparator: '',
40087 itemCls : 'x-form-item-display-none'
40095 * Ext JS Library 1.1.1
40096 * Copyright(c) 2006-2007, Ext JS, LLC.
40098 * Originally Released Under LGPL - original licence link has changed is not relivant.
40101 * <script type="text/javascript">
40105 * @class Roo.form.TriggerField
40106 * @extends Roo.form.TextField
40107 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
40108 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
40109 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
40110 * for which you can provide a custom implementation. For example:
40112 var trigger = new Roo.form.TriggerField();
40113 trigger.onTriggerClick = myTriggerFn;
40114 trigger.applyTo('my-field');
40117 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
40118 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
40119 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40120 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
40122 * Create a new TriggerField.
40123 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
40124 * to the base TextField)
40126 Roo.form.TriggerField = function(config){
40127 this.mimicing = false;
40128 Roo.form.TriggerField.superclass.constructor.call(this, config);
40131 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
40133 * @cfg {String} triggerClass A CSS class to apply to the trigger
40136 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40137 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
40139 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
40141 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
40145 /** @cfg {Boolean} grow @hide */
40146 /** @cfg {Number} growMin @hide */
40147 /** @cfg {Number} growMax @hide */
40153 autoSize: Roo.emptyFn,
40157 deferHeight : true,
40160 actionMode : 'wrap',
40162 onResize : function(w, h){
40163 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
40164 if(typeof w == 'number'){
40165 var x = w - this.trigger.getWidth();
40166 this.el.setWidth(this.adjustWidth('input', x));
40167 this.trigger.setStyle('left', x+'px');
40172 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40175 getResizeEl : function(){
40180 getPositionEl : function(){
40185 alignErrorIcon : function(){
40186 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40190 onRender : function(ct, position){
40191 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40192 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
40193 this.trigger = this.wrap.createChild(this.triggerConfig ||
40194 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
40195 if(this.hideTrigger){
40196 this.trigger.setDisplayed(false);
40198 this.initTrigger();
40200 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
40205 initTrigger : function(){
40206 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40207 this.trigger.addClassOnOver('x-form-trigger-over');
40208 this.trigger.addClassOnClick('x-form-trigger-click');
40212 onDestroy : function(){
40214 this.trigger.removeAllListeners();
40215 this.trigger.remove();
40218 this.wrap.remove();
40220 Roo.form.TriggerField.superclass.onDestroy.call(this);
40224 onFocus : function(){
40225 Roo.form.TriggerField.superclass.onFocus.call(this);
40226 if(!this.mimicing){
40227 this.wrap.addClass('x-trigger-wrap-focus');
40228 this.mimicing = true;
40229 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40230 if(this.monitorTab){
40231 this.el.on("keydown", this.checkTab, this);
40237 checkTab : function(e){
40238 if(e.getKey() == e.TAB){
40239 this.triggerBlur();
40244 onBlur : function(){
40249 mimicBlur : function(e, t){
40250 if(!this.wrap.contains(t) && this.validateBlur()){
40251 this.triggerBlur();
40256 triggerBlur : function(){
40257 this.mimicing = false;
40258 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40259 if(this.monitorTab){
40260 this.el.un("keydown", this.checkTab, this);
40262 this.wrap.removeClass('x-trigger-wrap-focus');
40263 Roo.form.TriggerField.superclass.onBlur.call(this);
40267 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40268 validateBlur : function(e, t){
40273 onDisable : function(){
40274 Roo.form.TriggerField.superclass.onDisable.call(this);
40276 this.wrap.addClass('x-item-disabled');
40281 onEnable : function(){
40282 Roo.form.TriggerField.superclass.onEnable.call(this);
40284 this.wrap.removeClass('x-item-disabled');
40289 onShow : function(){
40290 var ae = this.getActionEl();
40293 ae.dom.style.display = '';
40294 ae.dom.style.visibility = 'visible';
40300 onHide : function(){
40301 var ae = this.getActionEl();
40302 ae.dom.style.display = 'none';
40306 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40307 * by an implementing function.
40309 * @param {EventObject} e
40311 onTriggerClick : Roo.emptyFn
40314 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40315 // to be extended by an implementing class. For an example of implementing this class, see the custom
40316 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40317 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40318 initComponent : function(){
40319 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40321 this.triggerConfig = {
40322 tag:'span', cls:'x-form-twin-triggers', cn:[
40323 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40324 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40328 getTrigger : function(index){
40329 return this.triggers[index];
40332 initTrigger : function(){
40333 var ts = this.trigger.select('.x-form-trigger', true);
40334 this.wrap.setStyle('overflow', 'hidden');
40335 var triggerField = this;
40336 ts.each(function(t, all, index){
40337 t.hide = function(){
40338 var w = triggerField.wrap.getWidth();
40339 this.dom.style.display = 'none';
40340 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40342 t.show = function(){
40343 var w = triggerField.wrap.getWidth();
40344 this.dom.style.display = '';
40345 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40347 var triggerIndex = 'Trigger'+(index+1);
40349 if(this['hide'+triggerIndex]){
40350 t.dom.style.display = 'none';
40352 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40353 t.addClassOnOver('x-form-trigger-over');
40354 t.addClassOnClick('x-form-trigger-click');
40356 this.triggers = ts.elements;
40359 onTrigger1Click : Roo.emptyFn,
40360 onTrigger2Click : Roo.emptyFn
40363 * Ext JS Library 1.1.1
40364 * Copyright(c) 2006-2007, Ext JS, LLC.
40366 * Originally Released Under LGPL - original licence link has changed is not relivant.
40369 * <script type="text/javascript">
40373 * @class Roo.form.TextArea
40374 * @extends Roo.form.TextField
40375 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40376 * support for auto-sizing.
40378 * Creates a new TextArea
40379 * @param {Object} config Configuration options
40381 Roo.form.TextArea = function(config){
40382 Roo.form.TextArea.superclass.constructor.call(this, config);
40383 // these are provided exchanges for backwards compat
40384 // minHeight/maxHeight were replaced by growMin/growMax to be
40385 // compatible with TextField growing config values
40386 if(this.minHeight !== undefined){
40387 this.growMin = this.minHeight;
40389 if(this.maxHeight !== undefined){
40390 this.growMax = this.maxHeight;
40394 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40396 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40400 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40404 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40405 * in the field (equivalent to setting overflow: hidden, defaults to false)
40407 preventScrollbars: false,
40409 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40410 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40414 onRender : function(ct, position){
40416 this.defaultAutoCreate = {
40418 style:"width:300px;height:60px;",
40419 autocomplete: "new-password"
40422 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40424 this.textSizeEl = Roo.DomHelper.append(document.body, {
40425 tag: "pre", cls: "x-form-grow-sizer"
40427 if(this.preventScrollbars){
40428 this.el.setStyle("overflow", "hidden");
40430 this.el.setHeight(this.growMin);
40434 onDestroy : function(){
40435 if(this.textSizeEl){
40436 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40438 Roo.form.TextArea.superclass.onDestroy.call(this);
40442 onKeyUp : function(e){
40443 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40449 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40450 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40452 autoSize : function(){
40453 if(!this.grow || !this.textSizeEl){
40457 var v = el.dom.value;
40458 var ts = this.textSizeEl;
40461 ts.appendChild(document.createTextNode(v));
40464 Roo.fly(ts).setWidth(this.el.getWidth());
40466 v = "  ";
40469 v = v.replace(/\n/g, '<p> </p>');
40471 v += " \n ";
40474 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40475 if(h != this.lastHeight){
40476 this.lastHeight = h;
40477 this.el.setHeight(h);
40478 this.fireEvent("autosize", this, h);
40483 * Ext JS Library 1.1.1
40484 * Copyright(c) 2006-2007, Ext JS, LLC.
40486 * Originally Released Under LGPL - original licence link has changed is not relivant.
40489 * <script type="text/javascript">
40494 * @class Roo.form.NumberField
40495 * @extends Roo.form.TextField
40496 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40498 * Creates a new NumberField
40499 * @param {Object} config Configuration options
40501 Roo.form.NumberField = function(config){
40502 Roo.form.NumberField.superclass.constructor.call(this, config);
40505 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40507 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40509 fieldClass: "x-form-field x-form-num-field",
40511 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40513 allowDecimals : true,
40515 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40517 decimalSeparator : ".",
40519 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40521 decimalPrecision : 2,
40523 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40525 allowNegative : true,
40527 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40529 minValue : Number.NEGATIVE_INFINITY,
40531 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40533 maxValue : Number.MAX_VALUE,
40535 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40537 minText : "The minimum value for this field is {0}",
40539 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40541 maxText : "The maximum value for this field is {0}",
40543 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40544 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40546 nanText : "{0} is not a valid number",
40549 initEvents : function(){
40550 Roo.form.NumberField.superclass.initEvents.call(this);
40551 var allowed = "0123456789";
40552 if(this.allowDecimals){
40553 allowed += this.decimalSeparator;
40555 if(this.allowNegative){
40558 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40559 var keyPress = function(e){
40560 var k = e.getKey();
40561 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40564 var c = e.getCharCode();
40565 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40569 this.el.on("keypress", keyPress, this);
40573 validateValue : function(value){
40574 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40577 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40580 var num = this.parseValue(value);
40582 this.markInvalid(String.format(this.nanText, value));
40585 if(num < this.minValue){
40586 this.markInvalid(String.format(this.minText, this.minValue));
40589 if(num > this.maxValue){
40590 this.markInvalid(String.format(this.maxText, this.maxValue));
40596 getValue : function(){
40597 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40601 parseValue : function(value){
40602 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40603 return isNaN(value) ? '' : value;
40607 fixPrecision : function(value){
40608 var nan = isNaN(value);
40609 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40610 return nan ? '' : value;
40612 return parseFloat(value).toFixed(this.decimalPrecision);
40615 setValue : function(v){
40616 v = this.fixPrecision(v);
40617 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40621 decimalPrecisionFcn : function(v){
40622 return Math.floor(v);
40625 beforeBlur : function(){
40626 var v = this.parseValue(this.getRawValue());
40633 * Ext JS Library 1.1.1
40634 * Copyright(c) 2006-2007, Ext JS, LLC.
40636 * Originally Released Under LGPL - original licence link has changed is not relivant.
40639 * <script type="text/javascript">
40643 * @class Roo.form.DateField
40644 * @extends Roo.form.TriggerField
40645 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40647 * Create a new DateField
40648 * @param {Object} config
40650 Roo.form.DateField = function(config)
40652 Roo.form.DateField.superclass.constructor.call(this, config);
40658 * Fires when a date is selected
40659 * @param {Roo.form.DateField} combo This combo box
40660 * @param {Date} date The date selected
40667 if(typeof this.minValue == "string") {
40668 this.minValue = this.parseDate(this.minValue);
40670 if(typeof this.maxValue == "string") {
40671 this.maxValue = this.parseDate(this.maxValue);
40673 this.ddMatch = null;
40674 if(this.disabledDates){
40675 var dd = this.disabledDates;
40677 for(var i = 0; i < dd.length; i++){
40679 if(i != dd.length-1) {
40683 this.ddMatch = new RegExp(re + ")");
40687 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40689 * @cfg {String} format
40690 * The default date format string which can be overriden for localization support. The format must be
40691 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40695 * @cfg {String} altFormats
40696 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40697 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40699 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40701 * @cfg {Array} disabledDays
40702 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40704 disabledDays : null,
40706 * @cfg {String} disabledDaysText
40707 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40709 disabledDaysText : "Disabled",
40711 * @cfg {Array} disabledDates
40712 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40713 * expression so they are very powerful. Some examples:
40715 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40716 * <li>["03/08", "09/16"] would disable those days for every year</li>
40717 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40718 * <li>["03/../2006"] would disable every day in March 2006</li>
40719 * <li>["^03"] would disable every day in every March</li>
40721 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40722 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40724 disabledDates : null,
40726 * @cfg {String} disabledDatesText
40727 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40729 disabledDatesText : "Disabled",
40731 * @cfg {Date/String} minValue
40732 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40733 * valid format (defaults to null).
40737 * @cfg {Date/String} maxValue
40738 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40739 * valid format (defaults to null).
40743 * @cfg {String} minText
40744 * The error text to display when the date in the cell is before minValue (defaults to
40745 * 'The date in this field must be after {minValue}').
40747 minText : "The date in this field must be equal to or after {0}",
40749 * @cfg {String} maxText
40750 * The error text to display when the date in the cell is after maxValue (defaults to
40751 * 'The date in this field must be before {maxValue}').
40753 maxText : "The date in this field must be equal to or before {0}",
40755 * @cfg {String} invalidText
40756 * The error text to display when the date in the field is invalid (defaults to
40757 * '{value} is not a valid date - it must be in the format {format}').
40759 invalidText : "{0} is not a valid date - it must be in the format {1}",
40761 * @cfg {String} triggerClass
40762 * An additional CSS class used to style the trigger button. The trigger will always get the
40763 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40764 * which displays a calendar icon).
40766 triggerClass : 'x-form-date-trigger',
40770 * @cfg {Boolean} useIso
40771 * if enabled, then the date field will use a hidden field to store the
40772 * real value as iso formated date. default (false)
40776 * @cfg {String/Object} autoCreate
40777 * A DomHelper element spec, or true for a default element spec (defaults to
40778 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40781 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40784 hiddenField: false,
40786 onRender : function(ct, position)
40788 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40790 //this.el.dom.removeAttribute('name');
40791 Roo.log("Changing name?");
40792 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40793 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40795 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40796 // prevent input submission
40797 this.hiddenName = this.name;
40804 validateValue : function(value)
40806 value = this.formatDate(value);
40807 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40808 Roo.log('super failed');
40811 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40814 var svalue = value;
40815 value = this.parseDate(value);
40817 Roo.log('parse date failed' + svalue);
40818 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40821 var time = value.getTime();
40822 if(this.minValue && time < this.minValue.getTime()){
40823 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40826 if(this.maxValue && time > this.maxValue.getTime()){
40827 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40830 if(this.disabledDays){
40831 var day = value.getDay();
40832 for(var i = 0; i < this.disabledDays.length; i++) {
40833 if(day === this.disabledDays[i]){
40834 this.markInvalid(this.disabledDaysText);
40839 var fvalue = this.formatDate(value);
40840 if(this.ddMatch && this.ddMatch.test(fvalue)){
40841 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40848 // Provides logic to override the default TriggerField.validateBlur which just returns true
40849 validateBlur : function(){
40850 return !this.menu || !this.menu.isVisible();
40853 getName: function()
40855 // returns hidden if it's set..
40856 if (!this.rendered) {return ''};
40857 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40862 * Returns the current date value of the date field.
40863 * @return {Date} The date value
40865 getValue : function(){
40867 return this.hiddenField ?
40868 this.hiddenField.value :
40869 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40873 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40874 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40875 * (the default format used is "m/d/y").
40878 //All of these calls set the same date value (May 4, 2006)
40880 //Pass a date object:
40881 var dt = new Date('5/4/06');
40882 dateField.setValue(dt);
40884 //Pass a date string (default format):
40885 dateField.setValue('5/4/06');
40887 //Pass a date string (custom format):
40888 dateField.format = 'Y-m-d';
40889 dateField.setValue('2006-5-4');
40891 * @param {String/Date} date The date or valid date string
40893 setValue : function(date){
40894 if (this.hiddenField) {
40895 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40897 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40898 // make sure the value field is always stored as a date..
40899 this.value = this.parseDate(date);
40905 parseDate : function(value){
40906 if(!value || value instanceof Date){
40909 var v = Date.parseDate(value, this.format);
40910 if (!v && this.useIso) {
40911 v = Date.parseDate(value, 'Y-m-d');
40913 if(!v && this.altFormats){
40914 if(!this.altFormatsArray){
40915 this.altFormatsArray = this.altFormats.split("|");
40917 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40918 v = Date.parseDate(value, this.altFormatsArray[i]);
40925 formatDate : function(date, fmt){
40926 return (!date || !(date instanceof Date)) ?
40927 date : date.dateFormat(fmt || this.format);
40932 select: function(m, d){
40935 this.fireEvent('select', this, d);
40937 show : function(){ // retain focus styling
40941 this.focus.defer(10, this);
40942 var ml = this.menuListeners;
40943 this.menu.un("select", ml.select, this);
40944 this.menu.un("show", ml.show, this);
40945 this.menu.un("hide", ml.hide, this);
40950 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40951 onTriggerClick : function(){
40955 if(this.menu == null){
40956 this.menu = new Roo.menu.DateMenu();
40958 Roo.apply(this.menu.picker, {
40959 showClear: this.allowBlank,
40960 minDate : this.minValue,
40961 maxDate : this.maxValue,
40962 disabledDatesRE : this.ddMatch,
40963 disabledDatesText : this.disabledDatesText,
40964 disabledDays : this.disabledDays,
40965 disabledDaysText : this.disabledDaysText,
40966 format : this.useIso ? 'Y-m-d' : this.format,
40967 minText : String.format(this.minText, this.formatDate(this.minValue)),
40968 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40970 this.menu.on(Roo.apply({}, this.menuListeners, {
40973 this.menu.picker.setValue(this.getValue() || new Date());
40974 this.menu.show(this.el, "tl-bl?");
40977 beforeBlur : function(){
40978 var v = this.parseDate(this.getRawValue());
40988 isDirty : function() {
40989 if(this.disabled) {
40993 if(typeof(this.startValue) === 'undefined'){
40997 return String(this.getValue()) !== String(this.startValue);
41001 cleanLeadingSpace : function(e)
41008 * Ext JS Library 1.1.1
41009 * Copyright(c) 2006-2007, Ext JS, LLC.
41011 * Originally Released Under LGPL - original licence link has changed is not relivant.
41014 * <script type="text/javascript">
41018 * @class Roo.form.MonthField
41019 * @extends Roo.form.TriggerField
41020 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
41022 * Create a new MonthField
41023 * @param {Object} config
41025 Roo.form.MonthField = function(config){
41027 Roo.form.MonthField.superclass.constructor.call(this, config);
41033 * Fires when a date is selected
41034 * @param {Roo.form.MonthFieeld} combo This combo box
41035 * @param {Date} date The date selected
41042 if(typeof this.minValue == "string") {
41043 this.minValue = this.parseDate(this.minValue);
41045 if(typeof this.maxValue == "string") {
41046 this.maxValue = this.parseDate(this.maxValue);
41048 this.ddMatch = null;
41049 if(this.disabledDates){
41050 var dd = this.disabledDates;
41052 for(var i = 0; i < dd.length; i++){
41054 if(i != dd.length-1) {
41058 this.ddMatch = new RegExp(re + ")");
41062 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
41064 * @cfg {String} format
41065 * The default date format string which can be overriden for localization support. The format must be
41066 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41070 * @cfg {String} altFormats
41071 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
41072 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
41074 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
41076 * @cfg {Array} disabledDays
41077 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41079 disabledDays : [0,1,2,3,4,5,6],
41081 * @cfg {String} disabledDaysText
41082 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41084 disabledDaysText : "Disabled",
41086 * @cfg {Array} disabledDates
41087 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41088 * expression so they are very powerful. Some examples:
41090 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41091 * <li>["03/08", "09/16"] would disable those days for every year</li>
41092 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41093 * <li>["03/../2006"] would disable every day in March 2006</li>
41094 * <li>["^03"] would disable every day in every March</li>
41096 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41097 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41099 disabledDates : null,
41101 * @cfg {String} disabledDatesText
41102 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41104 disabledDatesText : "Disabled",
41106 * @cfg {Date/String} minValue
41107 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41108 * valid format (defaults to null).
41112 * @cfg {Date/String} maxValue
41113 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41114 * valid format (defaults to null).
41118 * @cfg {String} minText
41119 * The error text to display when the date in the cell is before minValue (defaults to
41120 * 'The date in this field must be after {minValue}').
41122 minText : "The date in this field must be equal to or after {0}",
41124 * @cfg {String} maxTextf
41125 * The error text to display when the date in the cell is after maxValue (defaults to
41126 * 'The date in this field must be before {maxValue}').
41128 maxText : "The date in this field must be equal to or before {0}",
41130 * @cfg {String} invalidText
41131 * The error text to display when the date in the field is invalid (defaults to
41132 * '{value} is not a valid date - it must be in the format {format}').
41134 invalidText : "{0} is not a valid date - it must be in the format {1}",
41136 * @cfg {String} triggerClass
41137 * An additional CSS class used to style the trigger button. The trigger will always get the
41138 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41139 * which displays a calendar icon).
41141 triggerClass : 'x-form-date-trigger',
41145 * @cfg {Boolean} useIso
41146 * if enabled, then the date field will use a hidden field to store the
41147 * real value as iso formated date. default (true)
41151 * @cfg {String/Object} autoCreate
41152 * A DomHelper element spec, or true for a default element spec (defaults to
41153 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41156 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
41159 hiddenField: false,
41161 hideMonthPicker : false,
41163 onRender : function(ct, position)
41165 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
41167 this.el.dom.removeAttribute('name');
41168 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41170 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41171 // prevent input submission
41172 this.hiddenName = this.name;
41179 validateValue : function(value)
41181 value = this.formatDate(value);
41182 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41185 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41188 var svalue = value;
41189 value = this.parseDate(value);
41191 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41194 var time = value.getTime();
41195 if(this.minValue && time < this.minValue.getTime()){
41196 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41199 if(this.maxValue && time > this.maxValue.getTime()){
41200 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41203 /*if(this.disabledDays){
41204 var day = value.getDay();
41205 for(var i = 0; i < this.disabledDays.length; i++) {
41206 if(day === this.disabledDays[i]){
41207 this.markInvalid(this.disabledDaysText);
41213 var fvalue = this.formatDate(value);
41214 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41215 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41223 // Provides logic to override the default TriggerField.validateBlur which just returns true
41224 validateBlur : function(){
41225 return !this.menu || !this.menu.isVisible();
41229 * Returns the current date value of the date field.
41230 * @return {Date} The date value
41232 getValue : function(){
41236 return this.hiddenField ?
41237 this.hiddenField.value :
41238 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41242 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41243 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41244 * (the default format used is "m/d/y").
41247 //All of these calls set the same date value (May 4, 2006)
41249 //Pass a date object:
41250 var dt = new Date('5/4/06');
41251 monthField.setValue(dt);
41253 //Pass a date string (default format):
41254 monthField.setValue('5/4/06');
41256 //Pass a date string (custom format):
41257 monthField.format = 'Y-m-d';
41258 monthField.setValue('2006-5-4');
41260 * @param {String/Date} date The date or valid date string
41262 setValue : function(date){
41263 Roo.log('month setValue' + date);
41264 // can only be first of month..
41266 var val = this.parseDate(date);
41268 if (this.hiddenField) {
41269 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41271 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41272 this.value = this.parseDate(date);
41276 parseDate : function(value){
41277 if(!value || value instanceof Date){
41278 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41281 var v = Date.parseDate(value, this.format);
41282 if (!v && this.useIso) {
41283 v = Date.parseDate(value, 'Y-m-d');
41287 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41291 if(!v && this.altFormats){
41292 if(!this.altFormatsArray){
41293 this.altFormatsArray = this.altFormats.split("|");
41295 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41296 v = Date.parseDate(value, this.altFormatsArray[i]);
41303 formatDate : function(date, fmt){
41304 return (!date || !(date instanceof Date)) ?
41305 date : date.dateFormat(fmt || this.format);
41310 select: function(m, d){
41312 this.fireEvent('select', this, d);
41314 show : function(){ // retain focus styling
41318 this.focus.defer(10, this);
41319 var ml = this.menuListeners;
41320 this.menu.un("select", ml.select, this);
41321 this.menu.un("show", ml.show, this);
41322 this.menu.un("hide", ml.hide, this);
41326 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41327 onTriggerClick : function(){
41331 if(this.menu == null){
41332 this.menu = new Roo.menu.DateMenu();
41336 Roo.apply(this.menu.picker, {
41338 showClear: this.allowBlank,
41339 minDate : this.minValue,
41340 maxDate : this.maxValue,
41341 disabledDatesRE : this.ddMatch,
41342 disabledDatesText : this.disabledDatesText,
41344 format : this.useIso ? 'Y-m-d' : this.format,
41345 minText : String.format(this.minText, this.formatDate(this.minValue)),
41346 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41349 this.menu.on(Roo.apply({}, this.menuListeners, {
41357 // hide month picker get's called when we called by 'before hide';
41359 var ignorehide = true;
41360 p.hideMonthPicker = function(disableAnim){
41364 if(this.monthPicker){
41365 Roo.log("hideMonthPicker called");
41366 if(disableAnim === true){
41367 this.monthPicker.hide();
41369 this.monthPicker.slideOut('t', {duration:.2});
41370 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41371 p.fireEvent("select", this, this.value);
41377 Roo.log('picker set value');
41378 Roo.log(this.getValue());
41379 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41380 m.show(this.el, 'tl-bl?');
41381 ignorehide = false;
41382 // this will trigger hideMonthPicker..
41385 // hidden the day picker
41386 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41392 p.showMonthPicker.defer(100, p);
41398 beforeBlur : function(){
41399 var v = this.parseDate(this.getRawValue());
41405 /** @cfg {Boolean} grow @hide */
41406 /** @cfg {Number} growMin @hide */
41407 /** @cfg {Number} growMax @hide */
41414 * Ext JS Library 1.1.1
41415 * Copyright(c) 2006-2007, Ext JS, LLC.
41417 * Originally Released Under LGPL - original licence link has changed is not relivant.
41420 * <script type="text/javascript">
41425 * @class Roo.form.ComboBox
41426 * @extends Roo.form.TriggerField
41427 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41429 * Create a new ComboBox.
41430 * @param {Object} config Configuration options
41432 Roo.form.ComboBox = function(config){
41433 Roo.form.ComboBox.superclass.constructor.call(this, config);
41437 * Fires when the dropdown list is expanded
41438 * @param {Roo.form.ComboBox} combo This combo box
41443 * Fires when the dropdown list is collapsed
41444 * @param {Roo.form.ComboBox} combo This combo box
41448 * @event beforeselect
41449 * Fires before a list item is selected. Return false to cancel the selection.
41450 * @param {Roo.form.ComboBox} combo This combo box
41451 * @param {Roo.data.Record} record The data record returned from the underlying store
41452 * @param {Number} index The index of the selected item in the dropdown list
41454 'beforeselect' : true,
41457 * Fires when a list item is selected
41458 * @param {Roo.form.ComboBox} combo This combo box
41459 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41460 * @param {Number} index The index of the selected item in the dropdown list
41464 * @event beforequery
41465 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41466 * The event object passed has these properties:
41467 * @param {Roo.form.ComboBox} combo This combo box
41468 * @param {String} query The query
41469 * @param {Boolean} forceAll true to force "all" query
41470 * @param {Boolean} cancel true to cancel the query
41471 * @param {Object} e The query event object
41473 'beforequery': true,
41476 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41477 * @param {Roo.form.ComboBox} combo This combo box
41482 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41483 * @param {Roo.form.ComboBox} combo This combo box
41484 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41490 if(this.transform){
41491 this.allowDomMove = false;
41492 var s = Roo.getDom(this.transform);
41493 if(!this.hiddenName){
41494 this.hiddenName = s.name;
41497 this.mode = 'local';
41498 var d = [], opts = s.options;
41499 for(var i = 0, len = opts.length;i < len; i++){
41501 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41503 this.value = value;
41505 d.push([value, o.text]);
41507 this.store = new Roo.data.SimpleStore({
41509 fields: ['value', 'text'],
41512 this.valueField = 'value';
41513 this.displayField = 'text';
41515 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41516 if(!this.lazyRender){
41517 this.target = true;
41518 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41519 s.parentNode.removeChild(s); // remove it
41520 this.render(this.el.parentNode);
41522 s.parentNode.removeChild(s); // remove it
41527 this.store = Roo.factory(this.store, Roo.data);
41530 this.selectedIndex = -1;
41531 if(this.mode == 'local'){
41532 if(config.queryDelay === undefined){
41533 this.queryDelay = 10;
41535 if(config.minChars === undefined){
41541 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41543 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41546 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41547 * rendering into an Roo.Editor, defaults to false)
41550 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41551 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41554 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41557 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41558 * the dropdown list (defaults to undefined, with no header element)
41562 * @cfg {String/Roo.Template} tpl The template to use to render the output
41566 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41568 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41570 listWidth: undefined,
41572 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41573 * mode = 'remote' or 'text' if mode = 'local')
41575 displayField: undefined,
41577 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41578 * mode = 'remote' or 'value' if mode = 'local').
41579 * Note: use of a valueField requires the user make a selection
41580 * in order for a value to be mapped.
41582 valueField: undefined,
41586 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41587 * field's data value (defaults to the underlying DOM element's name)
41589 hiddenName: undefined,
41591 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41595 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41597 selectedClass: 'x-combo-selected',
41599 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41600 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41601 * which displays a downward arrow icon).
41603 triggerClass : 'x-form-arrow-trigger',
41605 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41609 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41610 * anchor positions (defaults to 'tl-bl')
41612 listAlign: 'tl-bl?',
41614 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41618 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41619 * query specified by the allQuery config option (defaults to 'query')
41621 triggerAction: 'query',
41623 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41624 * (defaults to 4, does not apply if editable = false)
41628 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41629 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41633 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41634 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41638 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41639 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41643 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41644 * when editable = true (defaults to false)
41646 selectOnFocus:false,
41648 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41650 queryParam: 'query',
41652 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41653 * when mode = 'remote' (defaults to 'Loading...')
41655 loadingText: 'Loading...',
41657 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41661 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41665 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41666 * traditional select (defaults to true)
41670 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41674 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41678 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41679 * listWidth has a higher value)
41683 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41684 * allow the user to set arbitrary text into the field (defaults to false)
41686 forceSelection:false,
41688 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41689 * if typeAhead = true (defaults to 250)
41691 typeAheadDelay : 250,
41693 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41694 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41696 valueNotFoundText : undefined,
41698 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41700 blockFocus : false,
41703 * @cfg {Boolean} disableClear Disable showing of clear button.
41705 disableClear : false,
41707 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41709 alwaysQuery : false,
41715 // element that contains real text value.. (when hidden is used..)
41718 onRender : function(ct, position)
41720 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41722 if(this.hiddenName){
41723 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41725 this.hiddenField.value =
41726 this.hiddenValue !== undefined ? this.hiddenValue :
41727 this.value !== undefined ? this.value : '';
41729 // prevent input submission
41730 this.el.dom.removeAttribute('name');
41736 this.el.dom.setAttribute('autocomplete', 'off');
41739 var cls = 'x-combo-list';
41741 this.list = new Roo.Layer({
41742 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41745 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41746 this.list.setWidth(lw);
41747 this.list.swallowEvent('mousewheel');
41748 this.assetHeight = 0;
41751 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41752 this.assetHeight += this.header.getHeight();
41755 this.innerList = this.list.createChild({cls:cls+'-inner'});
41756 this.innerList.on('mouseover', this.onViewOver, this);
41757 this.innerList.on('mousemove', this.onViewMove, this);
41758 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41760 if(this.allowBlank && !this.pageSize && !this.disableClear){
41761 this.footer = this.list.createChild({cls:cls+'-ft'});
41762 this.pageTb = new Roo.Toolbar(this.footer);
41766 this.footer = this.list.createChild({cls:cls+'-ft'});
41767 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41768 {pageSize: this.pageSize});
41772 if (this.pageTb && this.allowBlank && !this.disableClear) {
41774 this.pageTb.add(new Roo.Toolbar.Fill(), {
41775 cls: 'x-btn-icon x-btn-clear',
41777 handler: function()
41780 _this.clearValue();
41781 _this.onSelect(false, -1);
41786 this.assetHeight += this.footer.getHeight();
41791 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41794 this.view = new Roo.View(this.innerList, this.tpl, {
41797 selectedClass: this.selectedClass
41800 this.view.on('click', this.onViewClick, this);
41802 this.store.on('beforeload', this.onBeforeLoad, this);
41803 this.store.on('load', this.onLoad, this);
41804 this.store.on('loadexception', this.onLoadException, this);
41806 if(this.resizable){
41807 this.resizer = new Roo.Resizable(this.list, {
41808 pinned:true, handles:'se'
41810 this.resizer.on('resize', function(r, w, h){
41811 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41812 this.listWidth = w;
41813 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41814 this.restrictHeight();
41816 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41818 if(!this.editable){
41819 this.editable = true;
41820 this.setEditable(false);
41824 if (typeof(this.events.add.listeners) != 'undefined') {
41826 this.addicon = this.wrap.createChild(
41827 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41829 this.addicon.on('click', function(e) {
41830 this.fireEvent('add', this);
41833 if (typeof(this.events.edit.listeners) != 'undefined') {
41835 this.editicon = this.wrap.createChild(
41836 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41837 if (this.addicon) {
41838 this.editicon.setStyle('margin-left', '40px');
41840 this.editicon.on('click', function(e) {
41842 // we fire even if inothing is selected..
41843 this.fireEvent('edit', this, this.lastData );
41853 initEvents : function(){
41854 Roo.form.ComboBox.superclass.initEvents.call(this);
41856 this.keyNav = new Roo.KeyNav(this.el, {
41857 "up" : function(e){
41858 this.inKeyMode = true;
41862 "down" : function(e){
41863 if(!this.isExpanded()){
41864 this.onTriggerClick();
41866 this.inKeyMode = true;
41871 "enter" : function(e){
41872 this.onViewClick();
41876 "esc" : function(e){
41880 "tab" : function(e){
41881 this.onViewClick(false);
41882 this.fireEvent("specialkey", this, e);
41888 doRelay : function(foo, bar, hname){
41889 if(hname == 'down' || this.scope.isExpanded()){
41890 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41897 this.queryDelay = Math.max(this.queryDelay || 10,
41898 this.mode == 'local' ? 10 : 250);
41899 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41900 if(this.typeAhead){
41901 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41903 if(this.editable !== false){
41904 this.el.on("keyup", this.onKeyUp, this);
41906 if(this.forceSelection){
41907 this.on('blur', this.doForce, this);
41911 onDestroy : function(){
41913 this.view.setStore(null);
41914 this.view.el.removeAllListeners();
41915 this.view.el.remove();
41916 this.view.purgeListeners();
41919 this.list.destroy();
41922 this.store.un('beforeload', this.onBeforeLoad, this);
41923 this.store.un('load', this.onLoad, this);
41924 this.store.un('loadexception', this.onLoadException, this);
41926 Roo.form.ComboBox.superclass.onDestroy.call(this);
41930 fireKey : function(e){
41931 if(e.isNavKeyPress() && !this.list.isVisible()){
41932 this.fireEvent("specialkey", this, e);
41937 onResize: function(w, h){
41938 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41940 if(typeof w != 'number'){
41941 // we do not handle it!?!?
41944 var tw = this.trigger.getWidth();
41945 tw += this.addicon ? this.addicon.getWidth() : 0;
41946 tw += this.editicon ? this.editicon.getWidth() : 0;
41948 this.el.setWidth( this.adjustWidth('input', x));
41950 this.trigger.setStyle('left', x+'px');
41952 if(this.list && this.listWidth === undefined){
41953 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41954 this.list.setWidth(lw);
41955 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41963 * Allow or prevent the user from directly editing the field text. If false is passed,
41964 * the user will only be able to select from the items defined in the dropdown list. This method
41965 * is the runtime equivalent of setting the 'editable' config option at config time.
41966 * @param {Boolean} value True to allow the user to directly edit the field text
41968 setEditable : function(value){
41969 if(value == this.editable){
41972 this.editable = value;
41974 this.el.dom.setAttribute('readOnly', true);
41975 this.el.on('mousedown', this.onTriggerClick, this);
41976 this.el.addClass('x-combo-noedit');
41978 this.el.dom.setAttribute('readOnly', false);
41979 this.el.un('mousedown', this.onTriggerClick, this);
41980 this.el.removeClass('x-combo-noedit');
41985 onBeforeLoad : function(){
41986 if(!this.hasFocus){
41989 this.innerList.update(this.loadingText ?
41990 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41991 this.restrictHeight();
41992 this.selectedIndex = -1;
41996 onLoad : function(){
41997 if(!this.hasFocus){
42000 if(this.store.getCount() > 0){
42002 this.restrictHeight();
42003 if(this.lastQuery == this.allQuery){
42005 this.el.dom.select();
42007 if(!this.selectByValue(this.value, true)){
42008 this.select(0, true);
42012 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
42013 this.taTask.delay(this.typeAheadDelay);
42017 this.onEmptyResults();
42022 onLoadException : function()
42025 Roo.log(this.store.reader.jsonData);
42026 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
42027 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
42033 onTypeAhead : function(){
42034 if(this.store.getCount() > 0){
42035 var r = this.store.getAt(0);
42036 var newValue = r.data[this.displayField];
42037 var len = newValue.length;
42038 var selStart = this.getRawValue().length;
42039 if(selStart != len){
42040 this.setRawValue(newValue);
42041 this.selectText(selStart, newValue.length);
42047 onSelect : function(record, index){
42048 if(this.fireEvent('beforeselect', this, record, index) !== false){
42049 this.setFromData(index > -1 ? record.data : false);
42051 this.fireEvent('select', this, record, index);
42056 * Returns the currently selected field value or empty string if no value is set.
42057 * @return {String} value The selected value
42059 getValue : function(){
42060 if(this.valueField){
42061 return typeof this.value != 'undefined' ? this.value : '';
42063 return Roo.form.ComboBox.superclass.getValue.call(this);
42067 * Clears any text/value currently set in the field
42069 clearValue : function(){
42070 if(this.hiddenField){
42071 this.hiddenField.value = '';
42074 this.setRawValue('');
42075 this.lastSelectionText = '';
42080 * Sets the specified value into the field. If the value finds a match, the corresponding record text
42081 * will be displayed in the field. If the value does not match the data value of an existing item,
42082 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
42083 * Otherwise the field will be blank (although the value will still be set).
42084 * @param {String} value The value to match
42086 setValue : function(v){
42088 if(this.valueField){
42089 var r = this.findRecord(this.valueField, v);
42091 text = r.data[this.displayField];
42092 }else if(this.valueNotFoundText !== undefined){
42093 text = this.valueNotFoundText;
42096 this.lastSelectionText = text;
42097 if(this.hiddenField){
42098 this.hiddenField.value = v;
42100 Roo.form.ComboBox.superclass.setValue.call(this, text);
42104 * @property {Object} the last set data for the element
42109 * Sets the value of the field based on a object which is related to the record format for the store.
42110 * @param {Object} value the value to set as. or false on reset?
42112 setFromData : function(o){
42113 var dv = ''; // display value
42114 var vv = ''; // value value..
42116 if (this.displayField) {
42117 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
42119 // this is an error condition!!!
42120 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
42123 if(this.valueField){
42124 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
42126 if(this.hiddenField){
42127 this.hiddenField.value = vv;
42129 this.lastSelectionText = dv;
42130 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42134 // no hidden field.. - we store the value in 'value', but still display
42135 // display field!!!!
42136 this.lastSelectionText = dv;
42137 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42143 reset : function(){
42144 // overridden so that last data is reset..
42145 this.setValue(this.resetValue);
42146 this.originalValue = this.getValue();
42147 this.clearInvalid();
42148 this.lastData = false;
42150 this.view.clearSelections();
42154 findRecord : function(prop, value){
42156 if(this.store.getCount() > 0){
42157 this.store.each(function(r){
42158 if(r.data[prop] == value){
42168 getName: function()
42170 // returns hidden if it's set..
42171 if (!this.rendered) {return ''};
42172 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42176 onViewMove : function(e, t){
42177 this.inKeyMode = false;
42181 onViewOver : function(e, t){
42182 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42185 var item = this.view.findItemFromChild(t);
42187 var index = this.view.indexOf(item);
42188 this.select(index, false);
42193 onViewClick : function(doFocus)
42195 var index = this.view.getSelectedIndexes()[0];
42196 var r = this.store.getAt(index);
42198 this.onSelect(r, index);
42200 if(doFocus !== false && !this.blockFocus){
42206 restrictHeight : function(){
42207 this.innerList.dom.style.height = '';
42208 var inner = this.innerList.dom;
42209 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42210 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42211 this.list.beginUpdate();
42212 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42213 this.list.alignTo(this.el, this.listAlign);
42214 this.list.endUpdate();
42218 onEmptyResults : function(){
42223 * Returns true if the dropdown list is expanded, else false.
42225 isExpanded : function(){
42226 return this.list.isVisible();
42230 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42231 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42232 * @param {String} value The data value of the item to select
42233 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42234 * selected item if it is not currently in view (defaults to true)
42235 * @return {Boolean} True if the value matched an item in the list, else false
42237 selectByValue : function(v, scrollIntoView){
42238 if(v !== undefined && v !== null){
42239 var r = this.findRecord(this.valueField || this.displayField, v);
42241 this.select(this.store.indexOf(r), scrollIntoView);
42249 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42250 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42251 * @param {Number} index The zero-based index of the list item to select
42252 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42253 * selected item if it is not currently in view (defaults to true)
42255 select : function(index, scrollIntoView){
42256 this.selectedIndex = index;
42257 this.view.select(index);
42258 if(scrollIntoView !== false){
42259 var el = this.view.getNode(index);
42261 this.innerList.scrollChildIntoView(el, false);
42267 selectNext : function(){
42268 var ct = this.store.getCount();
42270 if(this.selectedIndex == -1){
42272 }else if(this.selectedIndex < ct-1){
42273 this.select(this.selectedIndex+1);
42279 selectPrev : function(){
42280 var ct = this.store.getCount();
42282 if(this.selectedIndex == -1){
42284 }else if(this.selectedIndex != 0){
42285 this.select(this.selectedIndex-1);
42291 onKeyUp : function(e){
42292 if(this.editable !== false && !e.isSpecialKey()){
42293 this.lastKey = e.getKey();
42294 this.dqTask.delay(this.queryDelay);
42299 validateBlur : function(){
42300 return !this.list || !this.list.isVisible();
42304 initQuery : function(){
42305 this.doQuery(this.getRawValue());
42309 doForce : function(){
42310 if(this.el.dom.value.length > 0){
42311 this.el.dom.value =
42312 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42318 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42319 * query allowing the query action to be canceled if needed.
42320 * @param {String} query The SQL query to execute
42321 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42322 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42323 * saved in the current store (defaults to false)
42325 doQuery : function(q, forceAll){
42326 if(q === undefined || q === null){
42331 forceAll: forceAll,
42335 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42339 forceAll = qe.forceAll;
42340 if(forceAll === true || (q.length >= this.minChars)){
42341 if(this.lastQuery != q || this.alwaysQuery){
42342 this.lastQuery = q;
42343 if(this.mode == 'local'){
42344 this.selectedIndex = -1;
42346 this.store.clearFilter();
42348 this.store.filter(this.displayField, q);
42352 this.store.baseParams[this.queryParam] = q;
42354 params: this.getParams(q)
42359 this.selectedIndex = -1;
42366 getParams : function(q){
42368 //p[this.queryParam] = q;
42371 p.limit = this.pageSize;
42377 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42379 collapse : function(){
42380 if(!this.isExpanded()){
42384 Roo.get(document).un('mousedown', this.collapseIf, this);
42385 Roo.get(document).un('mousewheel', this.collapseIf, this);
42386 if (!this.editable) {
42387 Roo.get(document).un('keydown', this.listKeyPress, this);
42389 this.fireEvent('collapse', this);
42393 collapseIf : function(e){
42394 if(!e.within(this.wrap) && !e.within(this.list)){
42400 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42402 expand : function(){
42403 if(this.isExpanded() || !this.hasFocus){
42406 this.list.alignTo(this.el, this.listAlign);
42408 Roo.get(document).on('mousedown', this.collapseIf, this);
42409 Roo.get(document).on('mousewheel', this.collapseIf, this);
42410 if (!this.editable) {
42411 Roo.get(document).on('keydown', this.listKeyPress, this);
42414 this.fireEvent('expand', this);
42418 // Implements the default empty TriggerField.onTriggerClick function
42419 onTriggerClick : function(){
42423 if(this.isExpanded()){
42425 if (!this.blockFocus) {
42430 this.hasFocus = true;
42431 if(this.triggerAction == 'all') {
42432 this.doQuery(this.allQuery, true);
42434 this.doQuery(this.getRawValue());
42436 if (!this.blockFocus) {
42441 listKeyPress : function(e)
42443 //Roo.log('listkeypress');
42444 // scroll to first matching element based on key pres..
42445 if (e.isSpecialKey()) {
42448 var k = String.fromCharCode(e.getKey()).toUpperCase();
42451 var csel = this.view.getSelectedNodes();
42452 var cselitem = false;
42454 var ix = this.view.indexOf(csel[0]);
42455 cselitem = this.store.getAt(ix);
42456 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42462 this.store.each(function(v) {
42464 // start at existing selection.
42465 if (cselitem.id == v.id) {
42471 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42472 match = this.store.indexOf(v);
42477 if (match === false) {
42478 return true; // no more action?
42481 this.view.select(match);
42482 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42483 sn.scrollIntoView(sn.dom.parentNode, false);
42487 * @cfg {Boolean} grow
42491 * @cfg {Number} growMin
42495 * @cfg {Number} growMax
42503 * Copyright(c) 2010-2012, Roo J Solutions Limited
42510 * @class Roo.form.ComboBoxArray
42511 * @extends Roo.form.TextField
42512 * A facebook style adder... for lists of email / people / countries etc...
42513 * pick multiple items from a combo box, and shows each one.
42515 * Fred [x] Brian [x] [Pick another |v]
42518 * For this to work: it needs various extra information
42519 * - normal combo problay has
42521 * + displayField, valueField
42523 * For our purpose...
42526 * If we change from 'extends' to wrapping...
42533 * Create a new ComboBoxArray.
42534 * @param {Object} config Configuration options
42538 Roo.form.ComboBoxArray = function(config)
42542 * @event beforeremove
42543 * Fires before 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
42547 'beforeremove' : true,
42550 * Fires when remove the value from the list
42551 * @param {Roo.form.ComboBoxArray} _self This combo box array
42552 * @param {Roo.form.ComboBoxArray.Item} item removed item
42559 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42561 this.items = new Roo.util.MixedCollection(false);
42563 // construct the child combo...
42573 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42576 * @cfg {Roo.form.ComboBox} combo [required] The combo box that is wrapped
42581 // behavies liek a hiddne field
42582 inputType: 'hidden',
42584 * @cfg {Number} width The width of the box that displays the selected element
42591 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42595 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42597 hiddenName : false,
42599 * @cfg {String} seperator The value seperator normally ','
42603 // private the array of items that are displayed..
42605 // private - the hidden field el.
42607 // private - the filed el..
42610 //validateValue : function() { return true; }, // all values are ok!
42611 //onAddClick: function() { },
42613 onRender : function(ct, position)
42616 // create the standard hidden element
42617 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42620 // give fake names to child combo;
42621 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42622 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42624 this.combo = Roo.factory(this.combo, Roo.form);
42625 this.combo.onRender(ct, position);
42626 if (typeof(this.combo.width) != 'undefined') {
42627 this.combo.onResize(this.combo.width,0);
42630 this.combo.initEvents();
42632 // assigned so form know we need to do this..
42633 this.store = this.combo.store;
42634 this.valueField = this.combo.valueField;
42635 this.displayField = this.combo.displayField ;
42638 this.combo.wrap.addClass('x-cbarray-grp');
42640 var cbwrap = this.combo.wrap.createChild(
42641 {tag: 'div', cls: 'x-cbarray-cb'},
42646 this.hiddenEl = this.combo.wrap.createChild({
42647 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42649 this.el = this.combo.wrap.createChild({
42650 tag: 'input', type:'hidden' , name: this.name, value : ''
42652 // this.el.dom.removeAttribute("name");
42655 this.outerWrap = this.combo.wrap;
42656 this.wrap = cbwrap;
42658 this.outerWrap.setWidth(this.width);
42659 this.outerWrap.dom.removeChild(this.el.dom);
42661 this.wrap.dom.appendChild(this.el.dom);
42662 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42663 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42665 this.combo.trigger.setStyle('position','relative');
42666 this.combo.trigger.setStyle('left', '0px');
42667 this.combo.trigger.setStyle('top', '2px');
42669 this.combo.el.setStyle('vertical-align', 'text-bottom');
42671 //this.trigger.setStyle('vertical-align', 'top');
42673 // this should use the code from combo really... on('add' ....)
42677 this.adder = this.outerWrap.createChild(
42678 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42680 this.adder.on('click', function(e) {
42681 _t.fireEvent('adderclick', this, e);
42685 //this.adder.on('click', this.onAddClick, _t);
42688 this.combo.on('select', function(cb, rec, ix) {
42689 this.addItem(rec.data);
42692 cb.el.dom.value = '';
42693 //cb.lastData = rec.data;
42702 getName: function()
42704 // returns hidden if it's set..
42705 if (!this.rendered) {return ''};
42706 return this.hiddenName ? this.hiddenName : this.name;
42711 onResize: function(w, h){
42714 // not sure if this is needed..
42715 //this.combo.onResize(w,h);
42717 if(typeof w != 'number'){
42718 // we do not handle it!?!?
42721 var tw = this.combo.trigger.getWidth();
42722 tw += this.addicon ? this.addicon.getWidth() : 0;
42723 tw += this.editicon ? this.editicon.getWidth() : 0;
42725 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42727 this.combo.trigger.setStyle('left', '0px');
42729 if(this.list && this.listWidth === undefined){
42730 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42731 this.list.setWidth(lw);
42732 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42739 addItem: function(rec)
42741 var valueField = this.combo.valueField;
42742 var displayField = this.combo.displayField;
42744 if (this.items.indexOfKey(rec[valueField]) > -1) {
42745 //console.log("GOT " + rec.data.id);
42749 var x = new Roo.form.ComboBoxArray.Item({
42750 //id : rec[this.idField],
42752 displayField : displayField ,
42753 tipField : displayField ,
42757 this.items.add(rec[valueField],x);
42758 // add it before the element..
42759 this.updateHiddenEl();
42760 x.render(this.outerWrap, this.wrap.dom);
42761 // add the image handler..
42764 updateHiddenEl : function()
42767 if (!this.hiddenEl) {
42771 var idField = this.combo.valueField;
42773 this.items.each(function(f) {
42774 ar.push(f.data[idField]);
42776 this.hiddenEl.dom.value = ar.join(this.seperator);
42782 this.items.clear();
42784 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42788 this.el.dom.value = '';
42789 if (this.hiddenEl) {
42790 this.hiddenEl.dom.value = '';
42794 getValue: function()
42796 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42798 setValue: function(v) // not a valid action - must use addItems..
42803 if (this.store.isLocal && (typeof(v) == 'string')) {
42804 // then we can use the store to find the values..
42805 // comma seperated at present.. this needs to allow JSON based encoding..
42806 this.hiddenEl.value = v;
42808 Roo.each(v.split(this.seperator), function(k) {
42809 Roo.log("CHECK " + this.valueField + ',' + k);
42810 var li = this.store.query(this.valueField, k);
42815 add[this.valueField] = k;
42816 add[this.displayField] = li.item(0).data[this.displayField];
42822 if (typeof(v) == 'object' ) {
42823 // then let's assume it's an array of objects..
42824 Roo.each(v, function(l) {
42826 if (typeof(l) == 'string') {
42828 add[this.valueField] = l;
42829 add[this.displayField] = l
42838 setFromData: function(v)
42840 // this recieves an object, if setValues is called.
42842 this.el.dom.value = v[this.displayField];
42843 this.hiddenEl.dom.value = v[this.valueField];
42844 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42847 var kv = v[this.valueField];
42848 var dv = v[this.displayField];
42849 kv = typeof(kv) != 'string' ? '' : kv;
42850 dv = typeof(dv) != 'string' ? '' : dv;
42853 var keys = kv.split(this.seperator);
42854 var display = dv.split(this.seperator);
42855 for (var i = 0 ; i < keys.length; i++) {
42857 add[this.valueField] = keys[i];
42858 add[this.displayField] = display[i];
42866 * Validates the combox array value
42867 * @return {Boolean} True if the value is valid, else false
42869 validate : function(){
42870 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42871 this.clearInvalid();
42877 validateValue : function(value){
42878 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42886 isDirty : function() {
42887 if(this.disabled) {
42892 var d = Roo.decode(String(this.originalValue));
42894 return String(this.getValue()) !== String(this.originalValue);
42897 var originalValue = [];
42899 for (var i = 0; i < d.length; i++){
42900 originalValue.push(d[i][this.valueField]);
42903 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42912 * @class Roo.form.ComboBoxArray.Item
42913 * @extends Roo.BoxComponent
42914 * A selected item in the list
42915 * Fred [x] Brian [x] [Pick another |v]
42918 * Create a new item.
42919 * @param {Object} config Configuration options
42922 Roo.form.ComboBoxArray.Item = function(config) {
42923 config.id = Roo.id();
42924 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42927 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42930 displayField : false,
42934 defaultAutoCreate : {
42936 cls: 'x-cbarray-item',
42943 src : Roo.BLANK_IMAGE_URL ,
42951 onRender : function(ct, position)
42953 Roo.form.Field.superclass.onRender.call(this, ct, position);
42956 var cfg = this.getAutoCreate();
42957 this.el = ct.createChild(cfg, position);
42960 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42962 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42963 this.cb.renderer(this.data) :
42964 String.format('{0}',this.data[this.displayField]);
42967 this.el.child('div').dom.setAttribute('qtip',
42968 String.format('{0}',this.data[this.tipField])
42971 this.el.child('img').on('click', this.remove, this);
42975 remove : function()
42977 if(this.cb.disabled){
42981 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42982 this.cb.items.remove(this);
42983 this.el.child('img').un('click', this.remove, this);
42985 this.cb.updateHiddenEl();
42987 this.cb.fireEvent('remove', this.cb, this);
42992 * RooJS Library 1.1.1
42993 * Copyright(c) 2008-2011 Alan Knowles
43000 * @class Roo.form.ComboNested
43001 * @extends Roo.form.ComboBox
43002 * A combobox for that allows selection of nested items in a list,
43017 * Create a new ComboNested
43018 * @param {Object} config Configuration options
43020 Roo.form.ComboNested = function(config){
43021 Roo.form.ComboCheck.superclass.constructor.call(this, config);
43022 // should verify some data...
43024 // hiddenName = required..
43025 // displayField = required
43026 // valudField == required
43027 var req= [ 'hiddenName', 'displayField', 'valueField' ];
43029 Roo.each(req, function(e) {
43030 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
43031 throw "Roo.form.ComboNested : missing value for: " + e;
43038 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
43041 * @config {Number} max Number of columns to show
43046 list : null, // the outermost div..
43047 innerLists : null, // the
43051 loadingChildren : false,
43053 onRender : function(ct, position)
43055 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
43057 if(this.hiddenName){
43058 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
43060 this.hiddenField.value =
43061 this.hiddenValue !== undefined ? this.hiddenValue :
43062 this.value !== undefined ? this.value : '';
43064 // prevent input submission
43065 this.el.dom.removeAttribute('name');
43071 this.el.dom.setAttribute('autocomplete', 'off');
43074 var cls = 'x-combo-list';
43076 this.list = new Roo.Layer({
43077 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
43080 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
43081 this.list.setWidth(lw);
43082 this.list.swallowEvent('mousewheel');
43083 this.assetHeight = 0;
43086 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
43087 this.assetHeight += this.header.getHeight();
43089 this.innerLists = [];
43092 for (var i =0 ; i < this.maxColumns; i++) {
43093 this.onRenderList( cls, i);
43096 // always needs footer, as we are going to have an 'OK' button.
43097 this.footer = this.list.createChild({cls:cls+'-ft'});
43098 this.pageTb = new Roo.Toolbar(this.footer);
43103 handler: function()
43109 if ( this.allowBlank && !this.disableClear) {
43111 this.pageTb.add(new Roo.Toolbar.Fill(), {
43112 cls: 'x-btn-icon x-btn-clear',
43114 handler: function()
43117 _this.clearValue();
43118 _this.onSelect(false, -1);
43123 this.assetHeight += this.footer.getHeight();
43127 onRenderList : function ( cls, i)
43130 var lw = Math.floor(
43131 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43134 this.list.setWidth(lw); // default to '1'
43136 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
43137 //il.on('mouseover', this.onViewOver, this, { list: i });
43138 //il.on('mousemove', this.onViewMove, this, { list: i });
43140 il.setStyle({ 'overflow-x' : 'hidden'});
43143 this.tpl = new Roo.Template({
43144 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
43145 isEmpty: function (value, allValues) {
43147 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
43148 return dl ? 'has-children' : 'no-children'
43153 var store = this.store;
43155 store = new Roo.data.SimpleStore({
43156 //fields : this.store.reader.meta.fields,
43157 reader : this.store.reader,
43161 this.stores[i] = store;
43163 var view = this.views[i] = new Roo.View(
43169 selectedClass: this.selectedClass
43172 view.getEl().setWidth(lw);
43173 view.getEl().setStyle({
43174 position: i < 1 ? 'relative' : 'absolute',
43176 left: (i * lw ) + 'px',
43177 display : i > 0 ? 'none' : 'block'
43179 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
43180 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
43181 //view.on('click', this.onViewClick, this, { list : i });
43183 store.on('beforeload', this.onBeforeLoad, this);
43184 store.on('load', this.onLoad, this, { list : i});
43185 store.on('loadexception', this.onLoadException, this);
43187 // hide the other vies..
43193 restrictHeight : function()
43196 Roo.each(this.innerLists, function(il,i) {
43197 var el = this.views[i].getEl();
43198 el.dom.style.height = '';
43199 var inner = el.dom;
43200 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
43201 // only adjust heights on other ones..
43202 mh = Math.max(h, mh);
43205 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43206 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43213 this.list.beginUpdate();
43214 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43215 this.list.alignTo(this.el, this.listAlign);
43216 this.list.endUpdate();
43221 // -- store handlers..
43223 onBeforeLoad : function()
43225 if(!this.hasFocus){
43228 this.innerLists[0].update(this.loadingText ?
43229 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43230 this.restrictHeight();
43231 this.selectedIndex = -1;
43234 onLoad : function(a,b,c,d)
43236 if (!this.loadingChildren) {
43237 // then we are loading the top level. - hide the children
43238 for (var i = 1;i < this.views.length; i++) {
43239 this.views[i].getEl().setStyle({ display : 'none' });
43241 var lw = Math.floor(
43242 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43245 this.list.setWidth(lw); // default to '1'
43249 if(!this.hasFocus){
43253 if(this.store.getCount() > 0) {
43255 this.restrictHeight();
43257 this.onEmptyResults();
43260 if (!this.loadingChildren) {
43261 this.selectActive();
43264 this.stores[1].loadData([]);
43265 this.stores[2].loadData([]);
43274 onLoadException : function()
43277 Roo.log(this.store.reader.jsonData);
43278 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43279 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43284 // no cleaning of leading spaces on blur here.
43285 cleanLeadingSpace : function(e) { },
43288 onSelectChange : function (view, sels, opts )
43290 var ix = view.getSelectedIndexes();
43292 if (opts.list > this.maxColumns - 2) {
43293 if (view.store.getCount()< 1) {
43294 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43298 // used to clear ?? but if we are loading unselected
43299 this.setFromData(view.store.getAt(ix[0]).data);
43308 // this get's fired when trigger opens..
43309 // this.setFromData({});
43310 var str = this.stores[opts.list+1];
43311 str.data.clear(); // removeall wihtout the fire events..
43315 var rec = view.store.getAt(ix[0]);
43317 this.setFromData(rec.data);
43318 this.fireEvent('select', this, rec, ix[0]);
43320 var lw = Math.floor(
43322 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43323 ) / this.maxColumns
43325 this.loadingChildren = true;
43326 this.stores[opts.list+1].loadDataFromChildren( rec );
43327 this.loadingChildren = false;
43328 var dl = this.stores[opts.list+1]. getTotalCount();
43330 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43332 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43333 for (var i = opts.list+2; i < this.views.length;i++) {
43334 this.views[i].getEl().setStyle({ display : 'none' });
43337 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43338 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43340 if (this.isLoading) {
43341 // this.selectActive(opts.list);
43349 onDoubleClick : function()
43351 this.collapse(); //??
43359 recordToStack : function(store, prop, value, stack)
43361 var cstore = new Roo.data.SimpleStore({
43362 //fields : this.store.reader.meta.fields, // we need array reader.. for
43363 reader : this.store.reader,
43367 var record = false;
43369 if(store.getCount() < 1){
43372 store.each(function(r){
43373 if(r.data[prop] == value){
43378 if (r.data.cn && r.data.cn.length) {
43379 cstore.loadDataFromChildren( r);
43380 var cret = _this.recordToStack(cstore, prop, value, stack);
43381 if (cret !== false) {
43390 if (record == false) {
43393 stack.unshift(srec);
43398 * find the stack of stores that match our value.
43403 selectActive : function ()
43405 // if store is not loaded, then we will need to wait for that to happen first.
43407 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43408 for (var i = 0; i < stack.length; i++ ) {
43409 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43421 * Ext JS Library 1.1.1
43422 * Copyright(c) 2006-2007, Ext JS, LLC.
43424 * Originally Released Under LGPL - original licence link has changed is not relivant.
43427 * <script type="text/javascript">
43430 * @class Roo.form.Checkbox
43431 * @extends Roo.form.Field
43432 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43434 * Creates a new Checkbox
43435 * @param {Object} config Configuration options
43437 Roo.form.Checkbox = function(config){
43438 Roo.form.Checkbox.superclass.constructor.call(this, config);
43442 * Fires when the checkbox is checked or unchecked.
43443 * @param {Roo.form.Checkbox} this This checkbox
43444 * @param {Boolean} checked The new checked value
43450 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43452 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43454 focusClass : undefined,
43456 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43458 fieldClass: "x-form-field",
43460 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43464 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43465 * {tag: "input", type: "checkbox", autocomplete: "off"})
43467 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43469 * @cfg {String} boxLabel The text that appears beside the checkbox
43473 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43477 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43479 valueOff: '0', // value when not checked..
43481 actionMode : 'viewEl',
43484 itemCls : 'x-menu-check-item x-form-item',
43485 groupClass : 'x-menu-group-item',
43486 inputType : 'hidden',
43489 inSetChecked: false, // check that we are not calling self...
43491 inputElement: false, // real input element?
43492 basedOn: false, // ????
43494 isFormField: true, // not sure where this is needed!!!!
43496 onResize : function(){
43497 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43498 if(!this.boxLabel){
43499 this.el.alignTo(this.wrap, 'c-c');
43503 initEvents : function(){
43504 Roo.form.Checkbox.superclass.initEvents.call(this);
43505 this.el.on("click", this.onClick, this);
43506 this.el.on("change", this.onClick, this);
43510 getResizeEl : function(){
43514 getPositionEl : function(){
43519 onRender : function(ct, position){
43520 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43522 if(this.inputValue !== undefined){
43523 this.el.dom.value = this.inputValue;
43526 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43527 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43528 var viewEl = this.wrap.createChild({
43529 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43530 this.viewEl = viewEl;
43531 this.wrap.on('click', this.onClick, this);
43533 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43534 this.el.on('propertychange', this.setFromHidden, this); //ie
43539 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43540 // viewEl.on('click', this.onClick, this);
43542 //if(this.checked){
43543 this.setChecked(this.checked);
43545 //this.checked = this.el.dom;
43551 initValue : Roo.emptyFn,
43554 * Returns the checked state of the checkbox.
43555 * @return {Boolean} True if checked, else false
43557 getValue : function(){
43559 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43561 return this.valueOff;
43566 onClick : function(){
43567 if (this.disabled) {
43570 this.setChecked(!this.checked);
43572 //if(this.el.dom.checked != this.checked){
43573 // this.setValue(this.el.dom.checked);
43578 * Sets the checked state of the checkbox.
43579 * On is always based on a string comparison between inputValue and the param.
43580 * @param {Boolean/String} value - the value to set
43581 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43583 setValue : function(v,suppressEvent){
43586 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43587 //if(this.el && this.el.dom){
43588 // this.el.dom.checked = this.checked;
43589 // this.el.dom.defaultChecked = this.checked;
43591 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43592 //this.fireEvent("check", this, this.checked);
43595 setChecked : function(state,suppressEvent)
43597 if (this.inSetChecked) {
43598 this.checked = state;
43604 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43606 this.checked = state;
43607 if(suppressEvent !== true){
43608 this.fireEvent('check', this, state);
43610 this.inSetChecked = true;
43611 this.el.dom.value = state ? this.inputValue : this.valueOff;
43612 this.inSetChecked = false;
43615 // handle setting of hidden value by some other method!!?!?
43616 setFromHidden: function()
43621 //console.log("SET FROM HIDDEN");
43622 //alert('setFrom hidden');
43623 this.setValue(this.el.dom.value);
43626 onDestroy : function()
43629 Roo.get(this.viewEl).remove();
43632 Roo.form.Checkbox.superclass.onDestroy.call(this);
43635 setBoxLabel : function(str)
43637 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43642 * Ext JS Library 1.1.1
43643 * Copyright(c) 2006-2007, Ext JS, LLC.
43645 * Originally Released Under LGPL - original licence link has changed is not relivant.
43648 * <script type="text/javascript">
43652 * @class Roo.form.Radio
43653 * @extends Roo.form.Checkbox
43654 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43655 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43657 * Creates a new Radio
43658 * @param {Object} config Configuration options
43660 Roo.form.Radio = function(){
43661 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43663 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43664 inputType: 'radio',
43667 * If this radio is part of a group, it will return the selected value
43670 getGroupValue : function(){
43671 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43675 onRender : function(ct, position){
43676 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43678 if(this.inputValue !== undefined){
43679 this.el.dom.value = this.inputValue;
43682 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43683 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43684 //var viewEl = this.wrap.createChild({
43685 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43686 //this.viewEl = viewEl;
43687 //this.wrap.on('click', this.onClick, this);
43689 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43690 //this.el.on('propertychange', this.setFromHidden, this); //ie
43695 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43696 // viewEl.on('click', this.onClick, this);
43699 this.el.dom.checked = 'checked' ;
43705 });//<script type="text/javascript">
43708 * Based Ext JS Library 1.1.1
43709 * Copyright(c) 2006-2007, Ext JS, LLC.
43715 * @class Roo.HtmlEditorCore
43716 * @extends Roo.Component
43717 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43719 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43722 Roo.HtmlEditorCore = function(config){
43725 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43730 * @event initialize
43731 * Fires when the editor is fully initialized (including the iframe)
43732 * @param {Roo.HtmlEditorCore} this
43737 * Fires when the editor is first receives the focus. Any insertion must wait
43738 * until after this event.
43739 * @param {Roo.HtmlEditorCore} this
43743 * @event beforesync
43744 * Fires before the textarea is updated with content from the editor iframe. Return false
43745 * to cancel the sync.
43746 * @param {Roo.HtmlEditorCore} this
43747 * @param {String} html
43751 * @event beforepush
43752 * Fires before the iframe editor is updated with content from the textarea. Return false
43753 * to cancel the push.
43754 * @param {Roo.HtmlEditorCore} this
43755 * @param {String} html
43760 * Fires when the textarea is updated with content from the editor iframe.
43761 * @param {Roo.HtmlEditorCore} this
43762 * @param {String} html
43767 * Fires when the iframe editor is updated with content from the textarea.
43768 * @param {Roo.HtmlEditorCore} this
43769 * @param {String} html
43774 * @event editorevent
43775 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43776 * @param {Roo.HtmlEditorCore} this
43782 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43784 // defaults : white / black...
43785 this.applyBlacklists();
43792 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43796 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43802 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43807 * @cfg {Number} height (in pixels)
43811 * @cfg {Number} width (in pixels)
43816 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43819 stylesheets: false,
43822 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
43824 allowComments: false,
43828 // private properties
43829 validationEvent : false,
43831 initialized : false,
43833 sourceEditMode : false,
43834 onFocus : Roo.emptyFn,
43836 hideMode:'offsets',
43840 // blacklist + whitelisted elements..
43847 * Protected method that will not generally be called directly. It
43848 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43849 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43851 getDocMarkup : function(){
43855 // inherit styels from page...??
43856 if (this.stylesheets === false) {
43858 Roo.get(document.head).select('style').each(function(node) {
43859 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43862 Roo.get(document.head).select('link').each(function(node) {
43863 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43866 } else if (!this.stylesheets.length) {
43868 st = '<style type="text/css">' +
43869 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43872 for (var i in this.stylesheets) {
43873 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43878 st += '<style type="text/css">' +
43879 'IMG { cursor: pointer } ' +
43882 var cls = 'roo-htmleditor-body';
43884 if(this.bodyCls.length){
43885 cls += ' ' + this.bodyCls;
43888 return '<html><head>' + st +
43889 //<style type="text/css">' +
43890 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43892 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43896 onRender : function(ct, position)
43899 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43900 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43903 this.el.dom.style.border = '0 none';
43904 this.el.dom.setAttribute('tabIndex', -1);
43905 this.el.addClass('x-hidden hide');
43909 if(Roo.isIE){ // fix IE 1px bogus margin
43910 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43914 this.frameId = Roo.id();
43918 var iframe = this.owner.wrap.createChild({
43920 cls: 'form-control', // bootstrap..
43922 name: this.frameId,
43923 frameBorder : 'no',
43924 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43929 this.iframe = iframe.dom;
43931 this.assignDocWin();
43933 this.doc.designMode = 'on';
43936 this.doc.write(this.getDocMarkup());
43940 var task = { // must defer to wait for browser to be ready
43942 //console.log("run task?" + this.doc.readyState);
43943 this.assignDocWin();
43944 if(this.doc.body || this.doc.readyState == 'complete'){
43946 this.doc.designMode="on";
43950 Roo.TaskMgr.stop(task);
43951 this.initEditor.defer(10, this);
43958 Roo.TaskMgr.start(task);
43963 onResize : function(w, h)
43965 Roo.log('resize: ' +w + ',' + h );
43966 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43970 if(typeof w == 'number'){
43972 this.iframe.style.width = w + 'px';
43974 if(typeof h == 'number'){
43976 this.iframe.style.height = h + 'px';
43978 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43985 * Toggles the editor between standard and source edit mode.
43986 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43988 toggleSourceEdit : function(sourceEditMode){
43990 this.sourceEditMode = sourceEditMode === true;
43992 if(this.sourceEditMode){
43994 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43997 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43998 //this.iframe.className = '';
44001 //this.setSize(this.owner.wrap.getSize());
44002 //this.fireEvent('editmodechange', this, this.sourceEditMode);
44009 * Protected method that will not generally be called directly. If you need/want
44010 * custom HTML cleanup, this is the method you should override.
44011 * @param {String} html The HTML to be cleaned
44012 * return {String} The cleaned HTML
44014 cleanHtml : function(html){
44015 html = String(html);
44016 if(html.length > 5){
44017 if(Roo.isSafari){ // strip safari nonsense
44018 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
44021 if(html == ' '){
44028 * HTML Editor -> Textarea
44029 * Protected method that will not generally be called directly. Syncs the contents
44030 * of the editor iframe with the textarea.
44032 syncValue : function(){
44033 if(this.initialized){
44034 var bd = (this.doc.body || this.doc.documentElement);
44035 //this.cleanUpPaste(); -- this is done else where and causes havoc..
44036 var html = bd.innerHTML;
44038 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
44039 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
44041 html = '<div style="'+m[0]+'">' + html + '</div>';
44044 html = this.cleanHtml(html);
44045 // fix up the special chars.. normaly like back quotes in word...
44046 // however we do not want to do this with chinese..
44047 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
44049 var cc = match.charCodeAt();
44051 // Get the character value, handling surrogate pairs
44052 if (match.length == 2) {
44053 // It's a surrogate pair, calculate the Unicode code point
44054 var high = match.charCodeAt(0) - 0xD800;
44055 var low = match.charCodeAt(1) - 0xDC00;
44056 cc = (high * 0x400) + low + 0x10000;
44058 (cc >= 0x4E00 && cc < 0xA000 ) ||
44059 (cc >= 0x3400 && cc < 0x4E00 ) ||
44060 (cc >= 0xf900 && cc < 0xfb00 )
44065 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
44066 return "&#" + cc + ";";
44073 if(this.owner.fireEvent('beforesync', this, html) !== false){
44074 this.el.dom.value = html;
44075 this.owner.fireEvent('sync', this, html);
44081 * Protected method that will not generally be called directly. Pushes the value of the textarea
44082 * into the iframe editor.
44084 pushValue : function(){
44085 if(this.initialized){
44086 var v = this.el.dom.value.trim();
44088 // if(v.length < 1){
44092 if(this.owner.fireEvent('beforepush', this, v) !== false){
44093 var d = (this.doc.body || this.doc.documentElement);
44095 this.cleanUpPaste();
44096 this.el.dom.value = d.innerHTML;
44097 this.owner.fireEvent('push', this, v);
44103 deferFocus : function(){
44104 this.focus.defer(10, this);
44108 focus : function(){
44109 if(this.win && !this.sourceEditMode){
44116 assignDocWin: function()
44118 var iframe = this.iframe;
44121 this.doc = iframe.contentWindow.document;
44122 this.win = iframe.contentWindow;
44124 // if (!Roo.get(this.frameId)) {
44127 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44128 // this.win = Roo.get(this.frameId).dom.contentWindow;
44130 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
44134 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44135 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
44140 initEditor : function(){
44141 //console.log("INIT EDITOR");
44142 this.assignDocWin();
44146 this.doc.designMode="on";
44148 this.doc.write(this.getDocMarkup());
44151 var dbody = (this.doc.body || this.doc.documentElement);
44152 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
44153 // this copies styles from the containing element into thsi one..
44154 // not sure why we need all of this..
44155 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
44157 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
44158 //ss['background-attachment'] = 'fixed'; // w3c
44159 dbody.bgProperties = 'fixed'; // ie
44160 //Roo.DomHelper.applyStyles(dbody, ss);
44161 Roo.EventManager.on(this.doc, {
44162 //'mousedown': this.onEditorEvent,
44163 'mouseup': this.onEditorEvent,
44164 'dblclick': this.onEditorEvent,
44165 'click': this.onEditorEvent,
44166 'keyup': this.onEditorEvent,
44171 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
44173 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
44174 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
44176 this.initialized = true;
44178 this.owner.fireEvent('initialize', this);
44183 onDestroy : function(){
44189 //for (var i =0; i < this.toolbars.length;i++) {
44190 // // fixme - ask toolbars for heights?
44191 // this.toolbars[i].onDestroy();
44194 //this.wrap.dom.innerHTML = '';
44195 //this.wrap.remove();
44200 onFirstFocus : function(){
44202 this.assignDocWin();
44205 this.activated = true;
44208 if(Roo.isGecko){ // prevent silly gecko errors
44210 var s = this.win.getSelection();
44211 if(!s.focusNode || s.focusNode.nodeType != 3){
44212 var r = s.getRangeAt(0);
44213 r.selectNodeContents((this.doc.body || this.doc.documentElement));
44218 this.execCmd('useCSS', true);
44219 this.execCmd('styleWithCSS', false);
44222 this.owner.fireEvent('activate', this);
44226 adjustFont: function(btn){
44227 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44228 //if(Roo.isSafari){ // safari
44231 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44232 if(Roo.isSafari){ // safari
44233 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44234 v = (v < 10) ? 10 : v;
44235 v = (v > 48) ? 48 : v;
44236 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44241 v = Math.max(1, v+adjust);
44243 this.execCmd('FontSize', v );
44246 onEditorEvent : function(e)
44248 this.owner.fireEvent('editorevent', this, e);
44249 // this.updateToolbar();
44250 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44253 insertTag : function(tg)
44255 // could be a bit smarter... -> wrap the current selected tRoo..
44256 if (tg.toLowerCase() == 'span' ||
44257 tg.toLowerCase() == 'code' ||
44258 tg.toLowerCase() == 'sup' ||
44259 tg.toLowerCase() == 'sub'
44262 range = this.createRange(this.getSelection());
44263 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44264 wrappingNode.appendChild(range.extractContents());
44265 range.insertNode(wrappingNode);
44272 this.execCmd("formatblock", tg);
44276 insertText : function(txt)
44280 var range = this.createRange();
44281 range.deleteContents();
44282 //alert(Sender.getAttribute('label'));
44284 range.insertNode(this.doc.createTextNode(txt));
44290 * Executes a Midas editor command on the editor document and performs necessary focus and
44291 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44292 * @param {String} cmd The Midas command
44293 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44295 relayCmd : function(cmd, value){
44297 this.execCmd(cmd, value);
44298 this.owner.fireEvent('editorevent', this);
44299 //this.updateToolbar();
44300 this.owner.deferFocus();
44304 * Executes a Midas editor command directly on the editor document.
44305 * For visual commands, you should use {@link #relayCmd} instead.
44306 * <b>This should only be called after the editor is initialized.</b>
44307 * @param {String} cmd The Midas command
44308 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44310 execCmd : function(cmd, value){
44311 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44318 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44320 * @param {String} text | dom node..
44322 insertAtCursor : function(text)
44325 if(!this.activated){
44331 var r = this.doc.selection.createRange();
44342 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44346 // from jquery ui (MIT licenced)
44348 var win = this.win;
44350 if (win.getSelection && win.getSelection().getRangeAt) {
44351 range = win.getSelection().getRangeAt(0);
44352 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44353 range.insertNode(node);
44354 } else if (win.document.selection && win.document.selection.createRange) {
44355 // no firefox support
44356 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44357 win.document.selection.createRange().pasteHTML(txt);
44359 // no firefox support
44360 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44361 this.execCmd('InsertHTML', txt);
44370 mozKeyPress : function(e){
44372 var c = e.getCharCode(), cmd;
44375 c = String.fromCharCode(c).toLowerCase();
44389 this.cleanUpPaste.defer(100, this);
44397 e.preventDefault();
44405 fixKeys : function(){ // load time branching for fastest keydown performance
44407 return function(e){
44408 var k = e.getKey(), r;
44411 r = this.doc.selection.createRange();
44414 r.pasteHTML('    ');
44421 r = this.doc.selection.createRange();
44423 var target = r.parentElement();
44424 if(!target || target.tagName.toLowerCase() != 'li'){
44426 r.pasteHTML('<br />');
44432 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44433 this.cleanUpPaste.defer(100, this);
44439 }else if(Roo.isOpera){
44440 return function(e){
44441 var k = e.getKey();
44445 this.execCmd('InsertHTML','    ');
44448 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44449 this.cleanUpPaste.defer(100, this);
44454 }else if(Roo.isSafari){
44455 return function(e){
44456 var k = e.getKey();
44460 this.execCmd('InsertText','\t');
44464 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44465 this.cleanUpPaste.defer(100, this);
44473 getAllAncestors: function()
44475 var p = this.getSelectedNode();
44478 a.push(p); // push blank onto stack..
44479 p = this.getParentElement();
44483 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44487 a.push(this.doc.body);
44491 lastSelNode : false,
44494 getSelection : function()
44496 this.assignDocWin();
44497 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44500 getSelectedNode: function()
44502 // this may only work on Gecko!!!
44504 // should we cache this!!!!
44509 var range = this.createRange(this.getSelection()).cloneRange();
44512 var parent = range.parentElement();
44514 var testRange = range.duplicate();
44515 testRange.moveToElementText(parent);
44516 if (testRange.inRange(range)) {
44519 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44522 parent = parent.parentElement;
44527 // is ancestor a text element.
44528 var ac = range.commonAncestorContainer;
44529 if (ac.nodeType == 3) {
44530 ac = ac.parentNode;
44533 var ar = ac.childNodes;
44536 var other_nodes = [];
44537 var has_other_nodes = false;
44538 for (var i=0;i<ar.length;i++) {
44539 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44542 // fullly contained node.
44544 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44549 // probably selected..
44550 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44551 other_nodes.push(ar[i]);
44555 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44560 has_other_nodes = true;
44562 if (!nodes.length && other_nodes.length) {
44563 nodes= other_nodes;
44565 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44571 createRange: function(sel)
44573 // this has strange effects when using with
44574 // top toolbar - not sure if it's a great idea.
44575 //this.editor.contentWindow.focus();
44576 if (typeof sel != "undefined") {
44578 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44580 return this.doc.createRange();
44583 return this.doc.createRange();
44586 getParentElement: function()
44589 this.assignDocWin();
44590 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44592 var range = this.createRange(sel);
44595 var p = range.commonAncestorContainer;
44596 while (p.nodeType == 3) { // text node
44607 * Range intersection.. the hard stuff...
44611 * [ -- selected range --- ]
44615 * if end is before start or hits it. fail.
44616 * if start is after end or hits it fail.
44618 * if either hits (but other is outside. - then it's not
44624 // @see http://www.thismuchiknow.co.uk/?p=64.
44625 rangeIntersectsNode : function(range, node)
44627 var nodeRange = node.ownerDocument.createRange();
44629 nodeRange.selectNode(node);
44631 nodeRange.selectNodeContents(node);
44634 var rangeStartRange = range.cloneRange();
44635 rangeStartRange.collapse(true);
44637 var rangeEndRange = range.cloneRange();
44638 rangeEndRange.collapse(false);
44640 var nodeStartRange = nodeRange.cloneRange();
44641 nodeStartRange.collapse(true);
44643 var nodeEndRange = nodeRange.cloneRange();
44644 nodeEndRange.collapse(false);
44646 return rangeStartRange.compareBoundaryPoints(
44647 Range.START_TO_START, nodeEndRange) == -1 &&
44648 rangeEndRange.compareBoundaryPoints(
44649 Range.START_TO_START, nodeStartRange) == 1;
44653 rangeCompareNode : function(range, node)
44655 var nodeRange = node.ownerDocument.createRange();
44657 nodeRange.selectNode(node);
44659 nodeRange.selectNodeContents(node);
44663 range.collapse(true);
44665 nodeRange.collapse(true);
44667 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44668 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44670 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44672 var nodeIsBefore = ss == 1;
44673 var nodeIsAfter = ee == -1;
44675 if (nodeIsBefore && nodeIsAfter) {
44678 if (!nodeIsBefore && nodeIsAfter) {
44679 return 1; //right trailed.
44682 if (nodeIsBefore && !nodeIsAfter) {
44683 return 2; // left trailed.
44689 // private? - in a new class?
44690 cleanUpPaste : function()
44692 // cleans up the whole document..
44693 Roo.log('cleanuppaste');
44695 this.cleanUpChildren(this.doc.body);
44696 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44697 if (clean != this.doc.body.innerHTML) {
44698 this.doc.body.innerHTML = clean;
44703 cleanWordChars : function(input) {// change the chars to hex code
44704 var he = Roo.HtmlEditorCore;
44706 var output = input;
44707 Roo.each(he.swapCodes, function(sw) {
44708 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44710 output = output.replace(swapper, sw[1]);
44717 cleanUpChildren : function (n)
44719 if (!n.childNodes.length) {
44722 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44723 this.cleanUpChild(n.childNodes[i]);
44730 cleanUpChild : function (node)
44733 //console.log(node);
44734 if (node.nodeName == "#text") {
44735 // clean up silly Windows -- stuff?
44738 if (node.nodeName == "#comment") {
44739 if (!this.allowComments) {
44740 node.parentNode.removeChild(node);
44742 // clean up silly Windows -- stuff?
44745 var lcname = node.tagName.toLowerCase();
44746 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44747 // whitelist of tags..
44749 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44751 node.parentNode.removeChild(node);
44756 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44758 // spans with no attributes - just remove them..
44759 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44760 remove_keep_children = true;
44763 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44764 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44766 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44767 // remove_keep_children = true;
44770 if (remove_keep_children) {
44771 this.cleanUpChildren(node);
44772 // inserts everything just before this node...
44773 while (node.childNodes.length) {
44774 var cn = node.childNodes[0];
44775 node.removeChild(cn);
44776 node.parentNode.insertBefore(cn, node);
44778 node.parentNode.removeChild(node);
44782 if (!node.attributes || !node.attributes.length) {
44787 this.cleanUpChildren(node);
44791 function cleanAttr(n,v)
44794 if (v.match(/^\./) || v.match(/^\//)) {
44797 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44800 if (v.match(/^#/)) {
44803 if (v.match(/^\{/)) { // allow template editing.
44806 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44807 node.removeAttribute(n);
44811 var cwhite = this.cwhite;
44812 var cblack = this.cblack;
44814 function cleanStyle(n,v)
44816 if (v.match(/expression/)) { //XSS?? should we even bother..
44817 node.removeAttribute(n);
44821 var parts = v.split(/;/);
44824 Roo.each(parts, function(p) {
44825 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44829 var l = p.split(':').shift().replace(/\s+/g,'');
44830 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44832 if ( cwhite.length && cblack.indexOf(l) > -1) {
44833 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44834 //node.removeAttribute(n);
44838 // only allow 'c whitelisted system attributes'
44839 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44840 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44841 //node.removeAttribute(n);
44851 if (clean.length) {
44852 node.setAttribute(n, clean.join(';'));
44854 node.removeAttribute(n);
44860 for (var i = node.attributes.length-1; i > -1 ; i--) {
44861 var a = node.attributes[i];
44864 if (a.name.toLowerCase().substr(0,2)=='on') {
44865 node.removeAttribute(a.name);
44868 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44869 node.removeAttribute(a.name);
44872 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44873 cleanAttr(a.name,a.value); // fixme..
44876 if (a.name == 'style') {
44877 cleanStyle(a.name,a.value);
44880 /// clean up MS crap..
44881 // tecnically this should be a list of valid class'es..
44884 if (a.name == 'class') {
44885 if (a.value.match(/^Mso/)) {
44886 node.removeAttribute('class');
44889 if (a.value.match(/^body$/)) {
44890 node.removeAttribute('class');
44901 this.cleanUpChildren(node);
44907 * Clean up MS wordisms...
44909 cleanWord : function(node)
44912 this.cleanWord(this.doc.body);
44917 node.nodeName == 'SPAN' &&
44918 !node.hasAttributes() &&
44919 node.childNodes.length == 1 &&
44920 node.firstChild.nodeName == "#text"
44922 var textNode = node.firstChild;
44923 node.removeChild(textNode);
44924 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44925 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44927 node.parentNode.insertBefore(textNode, node);
44928 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44929 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44931 node.parentNode.removeChild(node);
44934 if (node.nodeName == "#text") {
44935 // clean up silly Windows -- stuff?
44938 if (node.nodeName == "#comment") {
44939 node.parentNode.removeChild(node);
44940 // clean up silly Windows -- stuff?
44944 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44945 node.parentNode.removeChild(node);
44948 //Roo.log(node.tagName);
44949 // remove - but keep children..
44950 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44951 //Roo.log('-- removed');
44952 while (node.childNodes.length) {
44953 var cn = node.childNodes[0];
44954 node.removeChild(cn);
44955 node.parentNode.insertBefore(cn, node);
44956 // move node to parent - and clean it..
44957 this.cleanWord(cn);
44959 node.parentNode.removeChild(node);
44960 /// no need to iterate chidlren = it's got none..
44961 //this.iterateChildren(node, this.cleanWord);
44965 if (node.className.length) {
44967 var cn = node.className.split(/\W+/);
44969 Roo.each(cn, function(cls) {
44970 if (cls.match(/Mso[a-zA-Z]+/)) {
44975 node.className = cna.length ? cna.join(' ') : '';
44977 node.removeAttribute("class");
44981 if (node.hasAttribute("lang")) {
44982 node.removeAttribute("lang");
44985 if (node.hasAttribute("style")) {
44987 var styles = node.getAttribute("style").split(";");
44989 Roo.each(styles, function(s) {
44990 if (!s.match(/:/)) {
44993 var kv = s.split(":");
44994 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44997 // what ever is left... we allow.
45000 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
45001 if (!nstyle.length) {
45002 node.removeAttribute('style');
45005 this.iterateChildren(node, this.cleanWord);
45011 * iterateChildren of a Node, calling fn each time, using this as the scole..
45012 * @param {DomNode} node node to iterate children of.
45013 * @param {Function} fn method of this class to call on each item.
45015 iterateChildren : function(node, fn)
45017 if (!node.childNodes.length) {
45020 for (var i = node.childNodes.length-1; i > -1 ; i--) {
45021 fn.call(this, node.childNodes[i])
45027 * cleanTableWidths.
45029 * Quite often pasting from word etc.. results in tables with column and widths.
45030 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
45033 cleanTableWidths : function(node)
45038 this.cleanTableWidths(this.doc.body);
45043 if (node.nodeName == "#text" || node.nodeName == "#comment") {
45046 Roo.log(node.tagName);
45047 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
45048 this.iterateChildren(node, this.cleanTableWidths);
45051 if (node.hasAttribute('width')) {
45052 node.removeAttribute('width');
45056 if (node.hasAttribute("style")) {
45059 var styles = node.getAttribute("style").split(";");
45061 Roo.each(styles, function(s) {
45062 if (!s.match(/:/)) {
45065 var kv = s.split(":");
45066 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
45069 // what ever is left... we allow.
45072 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
45073 if (!nstyle.length) {
45074 node.removeAttribute('style');
45078 this.iterateChildren(node, this.cleanTableWidths);
45086 domToHTML : function(currentElement, depth, nopadtext) {
45088 depth = depth || 0;
45089 nopadtext = nopadtext || false;
45091 if (!currentElement) {
45092 return this.domToHTML(this.doc.body);
45095 //Roo.log(currentElement);
45097 var allText = false;
45098 var nodeName = currentElement.nodeName;
45099 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
45101 if (nodeName == '#text') {
45103 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
45108 if (nodeName != 'BODY') {
45111 // Prints the node tagName, such as <A>, <IMG>, etc
45114 for(i = 0; i < currentElement.attributes.length;i++) {
45116 var aname = currentElement.attributes.item(i).name;
45117 if (!currentElement.attributes.item(i).value.length) {
45120 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
45123 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
45132 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
45135 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
45140 // Traverse the tree
45142 var currentElementChild = currentElement.childNodes.item(i);
45143 var allText = true;
45144 var innerHTML = '';
45146 while (currentElementChild) {
45147 // Formatting code (indent the tree so it looks nice on the screen)
45148 var nopad = nopadtext;
45149 if (lastnode == 'SPAN') {
45153 if (currentElementChild.nodeName == '#text') {
45154 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
45155 toadd = nopadtext ? toadd : toadd.trim();
45156 if (!nopad && toadd.length > 80) {
45157 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
45159 innerHTML += toadd;
45162 currentElementChild = currentElement.childNodes.item(i);
45168 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
45170 // Recursively traverse the tree structure of the child node
45171 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
45172 lastnode = currentElementChild.nodeName;
45174 currentElementChild=currentElement.childNodes.item(i);
45180 // The remaining code is mostly for formatting the tree
45181 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
45186 ret+= "</"+tagName+">";
45192 applyBlacklists : function()
45194 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
45195 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
45199 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
45200 if (b.indexOf(tag) > -1) {
45203 this.white.push(tag);
45207 Roo.each(w, function(tag) {
45208 if (b.indexOf(tag) > -1) {
45211 if (this.white.indexOf(tag) > -1) {
45214 this.white.push(tag);
45219 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
45220 if (w.indexOf(tag) > -1) {
45223 this.black.push(tag);
45227 Roo.each(b, function(tag) {
45228 if (w.indexOf(tag) > -1) {
45231 if (this.black.indexOf(tag) > -1) {
45234 this.black.push(tag);
45239 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45240 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45244 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45245 if (b.indexOf(tag) > -1) {
45248 this.cwhite.push(tag);
45252 Roo.each(w, function(tag) {
45253 if (b.indexOf(tag) > -1) {
45256 if (this.cwhite.indexOf(tag) > -1) {
45259 this.cwhite.push(tag);
45264 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45265 if (w.indexOf(tag) > -1) {
45268 this.cblack.push(tag);
45272 Roo.each(b, function(tag) {
45273 if (w.indexOf(tag) > -1) {
45276 if (this.cblack.indexOf(tag) > -1) {
45279 this.cblack.push(tag);
45284 setStylesheets : function(stylesheets)
45286 if(typeof(stylesheets) == 'string'){
45287 Roo.get(this.iframe.contentDocument.head).createChild({
45289 rel : 'stylesheet',
45298 Roo.each(stylesheets, function(s) {
45303 Roo.get(_this.iframe.contentDocument.head).createChild({
45305 rel : 'stylesheet',
45314 removeStylesheets : function()
45318 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45323 setStyle : function(style)
45325 Roo.get(this.iframe.contentDocument.head).createChild({
45334 // hide stuff that is not compatible
45348 * @event specialkey
45352 * @cfg {String} fieldClass @hide
45355 * @cfg {String} focusClass @hide
45358 * @cfg {String} autoCreate @hide
45361 * @cfg {String} inputType @hide
45364 * @cfg {String} invalidClass @hide
45367 * @cfg {String} invalidText @hide
45370 * @cfg {String} msgFx @hide
45373 * @cfg {String} validateOnBlur @hide
45377 Roo.HtmlEditorCore.white = [
45378 'area', 'br', 'img', 'input', 'hr', 'wbr',
45380 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45381 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45382 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45383 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45384 'table', 'ul', 'xmp',
45386 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45389 'dir', 'menu', 'ol', 'ul', 'dl',
45395 Roo.HtmlEditorCore.black = [
45396 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45398 'base', 'basefont', 'bgsound', 'blink', 'body',
45399 'frame', 'frameset', 'head', 'html', 'ilayer',
45400 'iframe', 'layer', 'link', 'meta', 'object',
45401 'script', 'style' ,'title', 'xml' // clean later..
45403 Roo.HtmlEditorCore.clean = [
45404 'script', 'style', 'title', 'xml'
45406 Roo.HtmlEditorCore.remove = [
45411 Roo.HtmlEditorCore.ablack = [
45415 Roo.HtmlEditorCore.aclean = [
45416 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45420 Roo.HtmlEditorCore.pwhite= [
45421 'http', 'https', 'mailto'
45424 // white listed style attributes.
45425 Roo.HtmlEditorCore.cwhite= [
45426 // 'text-align', /// default is to allow most things..
45432 // black listed style attributes.
45433 Roo.HtmlEditorCore.cblack= [
45434 // 'font-size' -- this can be set by the project
45438 Roo.HtmlEditorCore.swapCodes =[
45439 [ 8211, "–" ],
45440 [ 8212, "—" ],
45449 //<script type="text/javascript">
45452 * Ext JS Library 1.1.1
45453 * Copyright(c) 2006-2007, Ext JS, LLC.
45459 Roo.form.HtmlEditor = function(config){
45463 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45465 if (!this.toolbars) {
45466 this.toolbars = [];
45468 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45474 * @class Roo.form.HtmlEditor
45475 * @extends Roo.form.Field
45476 * Provides a lightweight HTML Editor component.
45478 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45480 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45481 * supported by this editor.</b><br/><br/>
45482 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45483 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45485 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45487 * @cfg {Boolean} clearUp
45491 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45496 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45501 * @cfg {Number} height (in pixels)
45505 * @cfg {Number} width (in pixels)
45510 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45513 stylesheets: false,
45517 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45522 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45528 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45533 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45538 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
45540 allowComments: false,
45545 // private properties
45546 validationEvent : false,
45548 initialized : false,
45551 onFocus : Roo.emptyFn,
45553 hideMode:'offsets',
45555 actionMode : 'container', // defaults to hiding it...
45557 defaultAutoCreate : { // modified by initCompnoent..
45559 style:"width:500px;height:300px;",
45560 autocomplete: "new-password"
45564 initComponent : function(){
45567 * @event initialize
45568 * Fires when the editor is fully initialized (including the iframe)
45569 * @param {HtmlEditor} this
45574 * Fires when the editor is first receives the focus. Any insertion must wait
45575 * until after this event.
45576 * @param {HtmlEditor} this
45580 * @event beforesync
45581 * Fires before the textarea is updated with content from the editor iframe. Return false
45582 * to cancel the sync.
45583 * @param {HtmlEditor} this
45584 * @param {String} html
45588 * @event beforepush
45589 * Fires before the iframe editor is updated with content from the textarea. Return false
45590 * to cancel the push.
45591 * @param {HtmlEditor} this
45592 * @param {String} html
45597 * Fires when the textarea is updated with content from the editor iframe.
45598 * @param {HtmlEditor} this
45599 * @param {String} html
45604 * Fires when the iframe editor is updated with content from the textarea.
45605 * @param {HtmlEditor} this
45606 * @param {String} html
45610 * @event editmodechange
45611 * Fires when the editor switches edit modes
45612 * @param {HtmlEditor} this
45613 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45615 editmodechange: true,
45617 * @event editorevent
45618 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45619 * @param {HtmlEditor} this
45623 * @event firstfocus
45624 * Fires when on first focus - needed by toolbars..
45625 * @param {HtmlEditor} this
45630 * Auto save the htmlEditor value as a file into Events
45631 * @param {HtmlEditor} this
45635 * @event savedpreview
45636 * preview the saved version of htmlEditor
45637 * @param {HtmlEditor} this
45639 savedpreview: true,
45642 * @event stylesheetsclick
45643 * Fires when press the Sytlesheets button
45644 * @param {Roo.HtmlEditorCore} this
45646 stylesheetsclick: true
45648 this.defaultAutoCreate = {
45650 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45651 autocomplete: "new-password"
45656 * Protected method that will not generally be called directly. It
45657 * is called when the editor creates its toolbar. Override this method if you need to
45658 * add custom toolbar buttons.
45659 * @param {HtmlEditor} editor
45661 createToolbar : function(editor){
45662 Roo.log("create toolbars");
45663 if (!editor.toolbars || !editor.toolbars.length) {
45664 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45667 for (var i =0 ; i < editor.toolbars.length;i++) {
45668 editor.toolbars[i] = Roo.factory(
45669 typeof(editor.toolbars[i]) == 'string' ?
45670 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45671 Roo.form.HtmlEditor);
45672 editor.toolbars[i].init(editor);
45680 onRender : function(ct, position)
45683 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45685 this.wrap = this.el.wrap({
45686 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45689 this.editorcore.onRender(ct, position);
45691 if (this.resizable) {
45692 this.resizeEl = new Roo.Resizable(this.wrap, {
45696 minHeight : this.height,
45697 height: this.height,
45698 handles : this.resizable,
45701 resize : function(r, w, h) {
45702 _t.onResize(w,h); // -something
45708 this.createToolbar(this);
45712 this.setSize(this.wrap.getSize());
45714 if (this.resizeEl) {
45715 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45716 // should trigger onReize..
45719 this.keyNav = new Roo.KeyNav(this.el, {
45721 "tab" : function(e){
45722 e.preventDefault();
45724 var value = this.getValue();
45726 var start = this.el.dom.selectionStart;
45727 var end = this.el.dom.selectionEnd;
45731 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45732 this.el.dom.setSelectionRange(end + 1, end + 1);
45736 var f = value.substring(0, start).split("\t");
45738 if(f.pop().length != 0){
45742 this.setValue(f.join("\t") + value.substring(end));
45743 this.el.dom.setSelectionRange(start - 1, start - 1);
45747 "home" : function(e){
45748 e.preventDefault();
45750 var curr = this.el.dom.selectionStart;
45751 var lines = this.getValue().split("\n");
45758 this.el.dom.setSelectionRange(0, 0);
45764 for (var i = 0; i < lines.length;i++) {
45765 pos += lines[i].length;
45775 pos -= lines[i].length;
45781 this.el.dom.setSelectionRange(pos, pos);
45785 this.el.dom.selectionStart = pos;
45786 this.el.dom.selectionEnd = curr;
45789 "end" : function(e){
45790 e.preventDefault();
45792 var curr = this.el.dom.selectionStart;
45793 var lines = this.getValue().split("\n");
45800 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45806 for (var i = 0; i < lines.length;i++) {
45808 pos += lines[i].length;
45822 this.el.dom.setSelectionRange(pos, pos);
45826 this.el.dom.selectionStart = curr;
45827 this.el.dom.selectionEnd = pos;
45832 doRelay : function(foo, bar, hname){
45833 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45839 // if(this.autosave && this.w){
45840 // this.autoSaveFn = setInterval(this.autosave, 1000);
45845 onResize : function(w, h)
45847 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45852 if(typeof w == 'number'){
45853 var aw = w - this.wrap.getFrameWidth('lr');
45854 this.el.setWidth(this.adjustWidth('textarea', aw));
45857 if(typeof h == 'number'){
45859 for (var i =0; i < this.toolbars.length;i++) {
45860 // fixme - ask toolbars for heights?
45861 tbh += this.toolbars[i].tb.el.getHeight();
45862 if (this.toolbars[i].footer) {
45863 tbh += this.toolbars[i].footer.el.getHeight();
45870 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45871 ah -= 5; // knock a few pixes off for look..
45873 this.el.setHeight(this.adjustWidth('textarea', ah));
45877 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45878 this.editorcore.onResize(ew,eh);
45883 * Toggles the editor between standard and source edit mode.
45884 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45886 toggleSourceEdit : function(sourceEditMode)
45888 this.editorcore.toggleSourceEdit(sourceEditMode);
45890 if(this.editorcore.sourceEditMode){
45891 Roo.log('editor - showing textarea');
45894 // Roo.log(this.syncValue());
45895 this.editorcore.syncValue();
45896 this.el.removeClass('x-hidden');
45897 this.el.dom.removeAttribute('tabIndex');
45900 for (var i = 0; i < this.toolbars.length; i++) {
45901 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45902 this.toolbars[i].tb.hide();
45903 this.toolbars[i].footer.hide();
45908 Roo.log('editor - hiding textarea');
45910 // Roo.log(this.pushValue());
45911 this.editorcore.pushValue();
45913 this.el.addClass('x-hidden');
45914 this.el.dom.setAttribute('tabIndex', -1);
45916 for (var i = 0; i < this.toolbars.length; i++) {
45917 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45918 this.toolbars[i].tb.show();
45919 this.toolbars[i].footer.show();
45923 //this.deferFocus();
45926 this.setSize(this.wrap.getSize());
45927 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45929 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45932 // private (for BoxComponent)
45933 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45935 // private (for BoxComponent)
45936 getResizeEl : function(){
45940 // private (for BoxComponent)
45941 getPositionEl : function(){
45946 initEvents : function(){
45947 this.originalValue = this.getValue();
45951 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45954 markInvalid : Roo.emptyFn,
45956 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45959 clearInvalid : Roo.emptyFn,
45961 setValue : function(v){
45962 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45963 this.editorcore.pushValue();
45968 deferFocus : function(){
45969 this.focus.defer(10, this);
45973 focus : function(){
45974 this.editorcore.focus();
45980 onDestroy : function(){
45986 for (var i =0; i < this.toolbars.length;i++) {
45987 // fixme - ask toolbars for heights?
45988 this.toolbars[i].onDestroy();
45991 this.wrap.dom.innerHTML = '';
45992 this.wrap.remove();
45997 onFirstFocus : function(){
45998 //Roo.log("onFirstFocus");
45999 this.editorcore.onFirstFocus();
46000 for (var i =0; i < this.toolbars.length;i++) {
46001 this.toolbars[i].onFirstFocus();
46007 syncValue : function()
46009 this.editorcore.syncValue();
46012 pushValue : function()
46014 this.editorcore.pushValue();
46017 setStylesheets : function(stylesheets)
46019 this.editorcore.setStylesheets(stylesheets);
46022 removeStylesheets : function()
46024 this.editorcore.removeStylesheets();
46028 // hide stuff that is not compatible
46042 * @event specialkey
46046 * @cfg {String} fieldClass @hide
46049 * @cfg {String} focusClass @hide
46052 * @cfg {String} autoCreate @hide
46055 * @cfg {String} inputType @hide
46058 * @cfg {String} invalidClass @hide
46061 * @cfg {String} invalidText @hide
46064 * @cfg {String} msgFx @hide
46067 * @cfg {String} validateOnBlur @hide
46071 // <script type="text/javascript">
46074 * Ext JS Library 1.1.1
46075 * Copyright(c) 2006-2007, Ext JS, LLC.
46081 * @class Roo.form.HtmlEditorToolbar1
46086 new Roo.form.HtmlEditor({
46089 new Roo.form.HtmlEditorToolbar1({
46090 disable : { fonts: 1 , format: 1, ..., ... , ...],
46096 * @cfg {Object} disable List of elements to disable..
46097 * @cfg {Array} btns List of additional buttons.
46101 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
46104 Roo.form.HtmlEditor.ToolbarStandard = function(config)
46107 Roo.apply(this, config);
46109 // default disabled, based on 'good practice'..
46110 this.disable = this.disable || {};
46111 Roo.applyIf(this.disable, {
46114 specialElements : true
46118 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46119 // dont call parent... till later.
46122 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
46129 editorcore : false,
46131 * @cfg {Object} disable List of toolbar elements to disable
46138 * @cfg {String} createLinkText The default text for the create link prompt
46140 createLinkText : 'Please enter the URL for the link:',
46142 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
46144 defaultLinkValue : 'http:/'+'/',
46148 * @cfg {Array} fontFamilies An array of available font families
46166 // "á" , ?? a acute?
46171 "°" // , // degrees
46173 // "é" , // e ecute
46174 // "ú" , // u ecute?
46177 specialElements : [
46179 text: "Insert Table",
46182 ihtml : '<table><tr><td>Cell</td></tr></table>'
46186 text: "Insert Image",
46189 ihtml : '<img src="about:blank"/>'
46198 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
46199 "input:submit", "input:button", "select", "textarea", "label" ],
46202 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
46204 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
46213 * @cfg {String} defaultFont default font to use.
46215 defaultFont: 'tahoma',
46217 fontSelect : false,
46220 formatCombo : false,
46222 init : function(editor)
46224 this.editor = editor;
46225 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46226 var editorcore = this.editorcore;
46230 var fid = editorcore.frameId;
46232 function btn(id, toggle, handler){
46233 var xid = fid + '-'+ id ;
46237 cls : 'x-btn-icon x-edit-'+id,
46238 enableToggle:toggle !== false,
46239 scope: _t, // was editor...
46240 handler:handler||_t.relayBtnCmd,
46241 clickEvent:'mousedown',
46242 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46249 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46251 // stop form submits
46252 tb.el.on('click', function(e){
46253 e.preventDefault(); // what does this do?
46256 if(!this.disable.font) { // && !Roo.isSafari){
46257 /* why no safari for fonts
46258 editor.fontSelect = tb.el.createChild({
46261 cls:'x-font-select',
46262 html: this.createFontOptions()
46265 editor.fontSelect.on('change', function(){
46266 var font = editor.fontSelect.dom.value;
46267 editor.relayCmd('fontname', font);
46268 editor.deferFocus();
46272 editor.fontSelect.dom,
46278 if(!this.disable.formats){
46279 this.formatCombo = new Roo.form.ComboBox({
46280 store: new Roo.data.SimpleStore({
46283 data : this.formats // from states.js
46287 //autoCreate : {tag: "div", size: "20"},
46288 displayField:'tag',
46292 triggerAction: 'all',
46293 emptyText:'Add tag',
46294 selectOnFocus:true,
46297 'select': function(c, r, i) {
46298 editorcore.insertTag(r.get('tag'));
46304 tb.addField(this.formatCombo);
46308 if(!this.disable.format){
46313 btn('strikethrough')
46316 if(!this.disable.fontSize){
46321 btn('increasefontsize', false, editorcore.adjustFont),
46322 btn('decreasefontsize', false, editorcore.adjustFont)
46327 if(!this.disable.colors){
46330 id:editorcore.frameId +'-forecolor',
46331 cls:'x-btn-icon x-edit-forecolor',
46332 clickEvent:'mousedown',
46333 tooltip: this.buttonTips['forecolor'] || undefined,
46335 menu : new Roo.menu.ColorMenu({
46336 allowReselect: true,
46337 focus: Roo.emptyFn,
46340 selectHandler: function(cp, color){
46341 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46342 editor.deferFocus();
46345 clickEvent:'mousedown'
46348 id:editorcore.frameId +'backcolor',
46349 cls:'x-btn-icon x-edit-backcolor',
46350 clickEvent:'mousedown',
46351 tooltip: this.buttonTips['backcolor'] || undefined,
46353 menu : new Roo.menu.ColorMenu({
46354 focus: Roo.emptyFn,
46357 allowReselect: true,
46358 selectHandler: function(cp, color){
46360 editorcore.execCmd('useCSS', false);
46361 editorcore.execCmd('hilitecolor', color);
46362 editorcore.execCmd('useCSS', true);
46363 editor.deferFocus();
46365 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46366 Roo.isSafari || Roo.isIE ? '#'+color : color);
46367 editor.deferFocus();
46371 clickEvent:'mousedown'
46376 // now add all the items...
46379 if(!this.disable.alignments){
46382 btn('justifyleft'),
46383 btn('justifycenter'),
46384 btn('justifyright')
46388 //if(!Roo.isSafari){
46389 if(!this.disable.links){
46392 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46396 if(!this.disable.lists){
46399 btn('insertorderedlist'),
46400 btn('insertunorderedlist')
46403 if(!this.disable.sourceEdit){
46406 btn('sourceedit', true, function(btn){
46407 this.toggleSourceEdit(btn.pressed);
46414 // special menu.. - needs to be tidied up..
46415 if (!this.disable.special) {
46418 cls: 'x-edit-none',
46424 for (var i =0; i < this.specialChars.length; i++) {
46425 smenu.menu.items.push({
46427 html: this.specialChars[i],
46428 handler: function(a,b) {
46429 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46430 //editor.insertAtCursor(a.html);
46444 if (!this.disable.cleanStyles) {
46446 cls: 'x-btn-icon x-btn-clear',
46452 for (var i =0; i < this.cleanStyles.length; i++) {
46453 cmenu.menu.items.push({
46454 actiontype : this.cleanStyles[i],
46455 html: 'Remove ' + this.cleanStyles[i],
46456 handler: function(a,b) {
46459 var c = Roo.get(editorcore.doc.body);
46460 c.select('[style]').each(function(s) {
46461 s.dom.style.removeProperty(a.actiontype);
46463 editorcore.syncValue();
46468 cmenu.menu.items.push({
46469 actiontype : 'tablewidths',
46470 html: 'Remove Table Widths',
46471 handler: function(a,b) {
46472 editorcore.cleanTableWidths();
46473 editorcore.syncValue();
46477 cmenu.menu.items.push({
46478 actiontype : 'word',
46479 html: 'Remove MS Word Formating',
46480 handler: function(a,b) {
46481 editorcore.cleanWord();
46482 editorcore.syncValue();
46487 cmenu.menu.items.push({
46488 actiontype : 'all',
46489 html: 'Remove All Styles',
46490 handler: function(a,b) {
46492 var c = Roo.get(editorcore.doc.body);
46493 c.select('[style]').each(function(s) {
46494 s.dom.removeAttribute('style');
46496 editorcore.syncValue();
46501 cmenu.menu.items.push({
46502 actiontype : 'all',
46503 html: 'Remove All CSS Classes',
46504 handler: function(a,b) {
46506 var c = Roo.get(editorcore.doc.body);
46507 c.select('[class]').each(function(s) {
46508 s.dom.removeAttribute('class');
46510 editorcore.cleanWord();
46511 editorcore.syncValue();
46516 cmenu.menu.items.push({
46517 actiontype : 'tidy',
46518 html: 'Tidy HTML Source',
46519 handler: function(a,b) {
46520 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46521 editorcore.syncValue();
46530 if (!this.disable.specialElements) {
46533 cls: 'x-edit-none',
46538 for (var i =0; i < this.specialElements.length; i++) {
46539 semenu.menu.items.push(
46541 handler: function(a,b) {
46542 editor.insertAtCursor(this.ihtml);
46544 }, this.specialElements[i])
46556 for(var i =0; i< this.btns.length;i++) {
46557 var b = Roo.factory(this.btns[i],Roo.form);
46558 b.cls = 'x-edit-none';
46560 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46561 b.cls += ' x-init-enable';
46564 b.scope = editorcore;
46572 // disable everything...
46574 this.tb.items.each(function(item){
46577 item.id != editorcore.frameId+ '-sourceedit' &&
46578 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46584 this.rendered = true;
46586 // the all the btns;
46587 editor.on('editorevent', this.updateToolbar, this);
46588 // other toolbars need to implement this..
46589 //editor.on('editmodechange', this.updateToolbar, this);
46593 relayBtnCmd : function(btn) {
46594 this.editorcore.relayCmd(btn.cmd);
46596 // private used internally
46597 createLink : function(){
46598 Roo.log("create link?");
46599 var url = prompt(this.createLinkText, this.defaultLinkValue);
46600 if(url && url != 'http:/'+'/'){
46601 this.editorcore.relayCmd('createlink', url);
46607 * Protected method that will not generally be called directly. It triggers
46608 * a toolbar update by reading the markup state of the current selection in the editor.
46610 updateToolbar: function(){
46612 if(!this.editorcore.activated){
46613 this.editor.onFirstFocus();
46617 var btns = this.tb.items.map,
46618 doc = this.editorcore.doc,
46619 frameId = this.editorcore.frameId;
46621 if(!this.disable.font && !Roo.isSafari){
46623 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46624 if(name != this.fontSelect.dom.value){
46625 this.fontSelect.dom.value = name;
46629 if(!this.disable.format){
46630 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46631 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46632 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46633 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46635 if(!this.disable.alignments){
46636 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46637 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46638 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46640 if(!Roo.isSafari && !this.disable.lists){
46641 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46642 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46645 var ans = this.editorcore.getAllAncestors();
46646 if (this.formatCombo) {
46649 var store = this.formatCombo.store;
46650 this.formatCombo.setValue("");
46651 for (var i =0; i < ans.length;i++) {
46652 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46654 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46662 // hides menus... - so this cant be on a menu...
46663 Roo.menu.MenuMgr.hideAll();
46665 //this.editorsyncValue();
46669 createFontOptions : function(){
46670 var buf = [], fs = this.fontFamilies, ff, lc;
46674 for(var i = 0, len = fs.length; i< len; i++){
46676 lc = ff.toLowerCase();
46678 '<option value="',lc,'" style="font-family:',ff,';"',
46679 (this.defaultFont == lc ? ' selected="true">' : '>'),
46684 return buf.join('');
46687 toggleSourceEdit : function(sourceEditMode){
46689 Roo.log("toolbar toogle");
46690 if(sourceEditMode === undefined){
46691 sourceEditMode = !this.sourceEditMode;
46693 this.sourceEditMode = sourceEditMode === true;
46694 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46695 // just toggle the button?
46696 if(btn.pressed !== this.sourceEditMode){
46697 btn.toggle(this.sourceEditMode);
46701 if(sourceEditMode){
46702 Roo.log("disabling buttons");
46703 this.tb.items.each(function(item){
46704 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46710 Roo.log("enabling buttons");
46711 if(this.editorcore.initialized){
46712 this.tb.items.each(function(item){
46718 Roo.log("calling toggole on editor");
46719 // tell the editor that it's been pressed..
46720 this.editor.toggleSourceEdit(sourceEditMode);
46724 * Object collection of toolbar tooltips for the buttons in the editor. The key
46725 * is the command id associated with that button and the value is a valid QuickTips object.
46730 title: 'Bold (Ctrl+B)',
46731 text: 'Make the selected text bold.',
46732 cls: 'x-html-editor-tip'
46735 title: 'Italic (Ctrl+I)',
46736 text: 'Make the selected text italic.',
46737 cls: 'x-html-editor-tip'
46745 title: 'Bold (Ctrl+B)',
46746 text: 'Make the selected text bold.',
46747 cls: 'x-html-editor-tip'
46750 title: 'Italic (Ctrl+I)',
46751 text: 'Make the selected text italic.',
46752 cls: 'x-html-editor-tip'
46755 title: 'Underline (Ctrl+U)',
46756 text: 'Underline the selected text.',
46757 cls: 'x-html-editor-tip'
46760 title: 'Strikethrough',
46761 text: 'Strikethrough the selected text.',
46762 cls: 'x-html-editor-tip'
46764 increasefontsize : {
46765 title: 'Grow Text',
46766 text: 'Increase the font size.',
46767 cls: 'x-html-editor-tip'
46769 decreasefontsize : {
46770 title: 'Shrink Text',
46771 text: 'Decrease the font size.',
46772 cls: 'x-html-editor-tip'
46775 title: 'Text Highlight Color',
46776 text: 'Change the background color of the selected text.',
46777 cls: 'x-html-editor-tip'
46780 title: 'Font Color',
46781 text: 'Change the color of the selected text.',
46782 cls: 'x-html-editor-tip'
46785 title: 'Align Text Left',
46786 text: 'Align text to the left.',
46787 cls: 'x-html-editor-tip'
46790 title: 'Center Text',
46791 text: 'Center text in the editor.',
46792 cls: 'x-html-editor-tip'
46795 title: 'Align Text Right',
46796 text: 'Align text to the right.',
46797 cls: 'x-html-editor-tip'
46799 insertunorderedlist : {
46800 title: 'Bullet List',
46801 text: 'Start a bulleted list.',
46802 cls: 'x-html-editor-tip'
46804 insertorderedlist : {
46805 title: 'Numbered List',
46806 text: 'Start a numbered list.',
46807 cls: 'x-html-editor-tip'
46810 title: 'Hyperlink',
46811 text: 'Make the selected text a hyperlink.',
46812 cls: 'x-html-editor-tip'
46815 title: 'Source Edit',
46816 text: 'Switch to source editing mode.',
46817 cls: 'x-html-editor-tip'
46821 onDestroy : function(){
46824 this.tb.items.each(function(item){
46826 item.menu.removeAll();
46828 item.menu.el.destroy();
46836 onFirstFocus: function() {
46837 this.tb.items.each(function(item){
46846 // <script type="text/javascript">
46849 * Ext JS Library 1.1.1
46850 * Copyright(c) 2006-2007, Ext JS, LLC.
46857 * @class Roo.form.HtmlEditor.ToolbarContext
46862 new Roo.form.HtmlEditor({
46865 { xtype: 'ToolbarStandard', styles : {} }
46866 { xtype: 'ToolbarContext', disable : {} }
46872 * @config : {Object} disable List of elements to disable.. (not done yet.)
46873 * @config : {Object} styles Map of styles available.
46877 Roo.form.HtmlEditor.ToolbarContext = function(config)
46880 Roo.apply(this, config);
46881 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46882 // dont call parent... till later.
46883 this.styles = this.styles || {};
46888 Roo.form.HtmlEditor.ToolbarContext.types = {
46900 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46966 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46971 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46981 style : 'fontFamily',
46982 displayField: 'display',
46983 optname : 'font-family',
47032 // should we really allow this??
47033 // should this just be
47044 style : 'fontFamily',
47045 displayField: 'display',
47046 optname : 'font-family',
47053 style : 'fontFamily',
47054 displayField: 'display',
47055 optname : 'font-family',
47062 style : 'fontFamily',
47063 displayField: 'display',
47064 optname : 'font-family',
47075 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
47076 Roo.form.HtmlEditor.ToolbarContext.stores = false;
47078 Roo.form.HtmlEditor.ToolbarContext.options = {
47080 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
47081 [ 'Courier New', 'Courier New'],
47082 [ 'Tahoma', 'Tahoma'],
47083 [ 'Times New Roman,serif', 'Times'],
47084 [ 'Verdana','Verdana' ]
47088 // fixme - these need to be configurable..
47091 //Roo.form.HtmlEditor.ToolbarContext.types
47094 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
47101 editorcore : false,
47103 * @cfg {Object} disable List of toolbar elements to disable
47108 * @cfg {Object} styles List of styles
47109 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
47111 * These must be defined in the page, so they get rendered correctly..
47122 init : function(editor)
47124 this.editor = editor;
47125 this.editorcore = editor.editorcore ? editor.editorcore : editor;
47126 var editorcore = this.editorcore;
47128 var fid = editorcore.frameId;
47130 function btn(id, toggle, handler){
47131 var xid = fid + '-'+ id ;
47135 cls : 'x-btn-icon x-edit-'+id,
47136 enableToggle:toggle !== false,
47137 scope: editorcore, // was editor...
47138 handler:handler||editorcore.relayBtnCmd,
47139 clickEvent:'mousedown',
47140 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47144 // create a new element.
47145 var wdiv = editor.wrap.createChild({
47147 }, editor.wrap.dom.firstChild.nextSibling, true);
47149 // can we do this more than once??
47151 // stop form submits
47154 // disable everything...
47155 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47156 this.toolbars = {};
47158 for (var i in ty) {
47160 this.toolbars[i] = this.buildToolbar(ty[i],i);
47162 this.tb = this.toolbars.BODY;
47164 this.buildFooter();
47165 this.footer.show();
47166 editor.on('hide', function( ) { this.footer.hide() }, this);
47167 editor.on('show', function( ) { this.footer.show() }, this);
47170 this.rendered = true;
47172 // the all the btns;
47173 editor.on('editorevent', this.updateToolbar, this);
47174 // other toolbars need to implement this..
47175 //editor.on('editmodechange', this.updateToolbar, this);
47181 * Protected method that will not generally be called directly. It triggers
47182 * a toolbar update by reading the markup state of the current selection in the editor.
47184 * Note you can force an update by calling on('editorevent', scope, false)
47186 updateToolbar: function(editor,ev,sel){
47189 // capture mouse up - this is handy for selecting images..
47190 // perhaps should go somewhere else...
47191 if(!this.editorcore.activated){
47192 this.editor.onFirstFocus();
47198 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
47199 // selectNode - might want to handle IE?
47201 (ev.type == 'mouseup' || ev.type == 'click' ) &&
47202 ev.target && ev.target.tagName == 'IMG') {
47203 // they have click on an image...
47204 // let's see if we can change the selection...
47207 var nodeRange = sel.ownerDocument.createRange();
47209 nodeRange.selectNode(sel);
47211 nodeRange.selectNodeContents(sel);
47213 //nodeRange.collapse(true);
47214 var s = this.editorcore.win.getSelection();
47215 s.removeAllRanges();
47216 s.addRange(nodeRange);
47220 var updateFooter = sel ? false : true;
47223 var ans = this.editorcore.getAllAncestors();
47226 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47229 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47230 sel = sel ? sel : this.editorcore.doc.body;
47231 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47234 // pick a menu that exists..
47235 var tn = sel.tagName.toUpperCase();
47236 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47238 tn = sel.tagName.toUpperCase();
47240 var lastSel = this.tb.selectedNode;
47242 this.tb.selectedNode = sel;
47244 // if current menu does not match..
47246 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47249 ///console.log("show: " + tn);
47250 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47253 this.tb.items.first().el.innerHTML = tn + ': ';
47256 // update attributes
47257 if (this.tb.fields) {
47258 this.tb.fields.each(function(e) {
47260 e.setValue(sel.style[e.stylename]);
47263 e.setValue(sel.getAttribute(e.attrname));
47267 var hasStyles = false;
47268 for(var i in this.styles) {
47275 var st = this.tb.fields.item(0);
47277 st.store.removeAll();
47280 var cn = sel.className.split(/\s+/);
47283 if (this.styles['*']) {
47285 Roo.each(this.styles['*'], function(v) {
47286 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47289 if (this.styles[tn]) {
47290 Roo.each(this.styles[tn], function(v) {
47291 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47295 st.store.loadData(avs);
47299 // flag our selected Node.
47300 this.tb.selectedNode = sel;
47303 Roo.menu.MenuMgr.hideAll();
47307 if (!updateFooter) {
47308 //this.footDisp.dom.innerHTML = '';
47311 // update the footer
47315 this.footerEls = ans.reverse();
47316 Roo.each(this.footerEls, function(a,i) {
47317 if (!a) { return; }
47318 html += html.length ? ' > ' : '';
47320 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47325 var sz = this.footDisp.up('td').getSize();
47326 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47327 this.footDisp.dom.style.marginLeft = '5px';
47329 this.footDisp.dom.style.overflow = 'hidden';
47331 this.footDisp.dom.innerHTML = html;
47333 //this.editorsyncValue();
47340 onDestroy : function(){
47343 this.tb.items.each(function(item){
47345 item.menu.removeAll();
47347 item.menu.el.destroy();
47355 onFirstFocus: function() {
47356 // need to do this for all the toolbars..
47357 this.tb.items.each(function(item){
47361 buildToolbar: function(tlist, nm)
47363 var editor = this.editor;
47364 var editorcore = this.editorcore;
47365 // create a new element.
47366 var wdiv = editor.wrap.createChild({
47368 }, editor.wrap.dom.firstChild.nextSibling, true);
47371 var tb = new Roo.Toolbar(wdiv);
47374 tb.add(nm+ ": ");
47377 for(var i in this.styles) {
47382 if (styles && styles.length) {
47384 // this needs a multi-select checkbox...
47385 tb.addField( new Roo.form.ComboBox({
47386 store: new Roo.data.SimpleStore({
47388 fields: ['val', 'selected'],
47391 name : '-roo-edit-className',
47392 attrname : 'className',
47393 displayField: 'val',
47397 triggerAction: 'all',
47398 emptyText:'Select Style',
47399 selectOnFocus:true,
47402 'select': function(c, r, i) {
47403 // initial support only for on class per el..
47404 tb.selectedNode.className = r ? r.get('val') : '';
47405 editorcore.syncValue();
47412 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47413 var tbops = tbc.options;
47415 for (var i in tlist) {
47417 var item = tlist[i];
47418 tb.add(item.title + ": ");
47421 //optname == used so you can configure the options available..
47422 var opts = item.opts ? item.opts : false;
47423 if (item.optname) {
47424 opts = tbops[item.optname];
47429 // opts == pulldown..
47430 tb.addField( new Roo.form.ComboBox({
47431 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47433 fields: ['val', 'display'],
47436 name : '-roo-edit-' + i,
47438 stylename : item.style ? item.style : false,
47439 displayField: item.displayField ? item.displayField : 'val',
47440 valueField : 'val',
47442 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47444 triggerAction: 'all',
47445 emptyText:'Select',
47446 selectOnFocus:true,
47447 width: item.width ? item.width : 130,
47449 'select': function(c, r, i) {
47451 tb.selectedNode.style[c.stylename] = r.get('val');
47454 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47463 tb.addField( new Roo.form.TextField({
47466 //allowBlank:false,
47471 tb.addField( new Roo.form.TextField({
47472 name: '-roo-edit-' + i,
47479 'change' : function(f, nv, ov) {
47480 tb.selectedNode.setAttribute(f.attrname, nv);
47481 editorcore.syncValue();
47494 text: 'Stylesheets',
47497 click : function ()
47499 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47507 text: 'Remove Tag',
47510 click : function ()
47513 // undo does not work.
47515 var sn = tb.selectedNode;
47517 var pn = sn.parentNode;
47519 var stn = sn.childNodes[0];
47520 var en = sn.childNodes[sn.childNodes.length - 1 ];
47521 while (sn.childNodes.length) {
47522 var node = sn.childNodes[0];
47523 sn.removeChild(node);
47525 pn.insertBefore(node, sn);
47528 pn.removeChild(sn);
47529 var range = editorcore.createRange();
47531 range.setStart(stn,0);
47532 range.setEnd(en,0); //????
47533 //range.selectNode(sel);
47536 var selection = editorcore.getSelection();
47537 selection.removeAllRanges();
47538 selection.addRange(range);
47542 //_this.updateToolbar(null, null, pn);
47543 _this.updateToolbar(null, null, null);
47544 _this.footDisp.dom.innerHTML = '';
47554 tb.el.on('click', function(e){
47555 e.preventDefault(); // what does this do?
47557 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47560 // dont need to disable them... as they will get hidden
47565 buildFooter : function()
47568 var fel = this.editor.wrap.createChild();
47569 this.footer = new Roo.Toolbar(fel);
47570 // toolbar has scrolly on left / right?
47571 var footDisp= new Roo.Toolbar.Fill();
47577 handler : function() {
47578 _t.footDisp.scrollTo('left',0,true)
47582 this.footer.add( footDisp );
47587 handler : function() {
47589 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47593 var fel = Roo.get(footDisp.el);
47594 fel.addClass('x-editor-context');
47595 this.footDispWrap = fel;
47596 this.footDispWrap.overflow = 'hidden';
47598 this.footDisp = fel.createChild();
47599 this.footDispWrap.on('click', this.onContextClick, this)
47603 onContextClick : function (ev,dom)
47605 ev.preventDefault();
47606 var cn = dom.className;
47608 if (!cn.match(/x-ed-loc-/)) {
47611 var n = cn.split('-').pop();
47612 var ans = this.footerEls;
47616 var range = this.editorcore.createRange();
47618 range.selectNodeContents(sel);
47619 //range.selectNode(sel);
47622 var selection = this.editorcore.getSelection();
47623 selection.removeAllRanges();
47624 selection.addRange(range);
47628 this.updateToolbar(null, null, sel);
47645 * Ext JS Library 1.1.1
47646 * Copyright(c) 2006-2007, Ext JS, LLC.
47648 * Originally Released Under LGPL - original licence link has changed is not relivant.
47651 * <script type="text/javascript">
47655 * @class Roo.form.BasicForm
47656 * @extends Roo.util.Observable
47657 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47659 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47660 * @param {Object} config Configuration options
47662 Roo.form.BasicForm = function(el, config){
47663 this.allItems = [];
47664 this.childForms = [];
47665 Roo.apply(this, config);
47667 * The Roo.form.Field items in this form.
47668 * @type MixedCollection
47672 this.items = new Roo.util.MixedCollection(false, function(o){
47673 return o.id || (o.id = Roo.id());
47677 * @event beforeaction
47678 * Fires before any action is performed. Return false to cancel the action.
47679 * @param {Form} this
47680 * @param {Action} action The action to be performed
47682 beforeaction: true,
47684 * @event actionfailed
47685 * Fires when an action fails.
47686 * @param {Form} this
47687 * @param {Action} action The action that failed
47689 actionfailed : true,
47691 * @event actioncomplete
47692 * Fires when an action is completed.
47693 * @param {Form} this
47694 * @param {Action} action The action that completed
47696 actioncomplete : true
47701 Roo.form.BasicForm.superclass.constructor.call(this);
47703 Roo.form.BasicForm.popover.apply();
47706 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47708 * @cfg {String} method
47709 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47712 * @cfg {DataReader} reader
47713 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47714 * This is optional as there is built-in support for processing JSON.
47717 * @cfg {DataReader} errorReader
47718 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47719 * This is completely optional as there is built-in support for processing JSON.
47722 * @cfg {String} url
47723 * The URL to use for form actions if one isn't supplied in the action options.
47726 * @cfg {Boolean} fileUpload
47727 * Set to true if this form is a file upload.
47731 * @cfg {Object} baseParams
47732 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47737 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47742 activeAction : null,
47745 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47746 * or setValues() data instead of when the form was first created.
47748 trackResetOnLoad : false,
47752 * childForms - used for multi-tab forms
47755 childForms : false,
47758 * allItems - full list of fields.
47764 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47765 * element by passing it or its id or mask the form itself by passing in true.
47768 waitMsgTarget : false,
47773 disableMask : false,
47776 * @cfg {Boolean} errorMask (true|false) default false
47781 * @cfg {Number} maskOffset Default 100
47786 initEl : function(el){
47787 this.el = Roo.get(el);
47788 this.id = this.el.id || Roo.id();
47789 this.el.on('submit', this.onSubmit, this);
47790 this.el.addClass('x-form');
47794 onSubmit : function(e){
47799 * Returns true if client-side validation on the form is successful.
47802 isValid : function(){
47804 var target = false;
47805 this.items.each(function(f){
47812 if(!target && f.el.isVisible(true)){
47817 if(this.errorMask && !valid){
47818 Roo.form.BasicForm.popover.mask(this, target);
47824 * Returns array of invalid form fields.
47828 invalidFields : function()
47831 this.items.each(function(f){
47844 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47847 isDirty : function(){
47849 this.items.each(function(f){
47859 * Returns true if any fields in this form have changed since their original load. (New version)
47863 hasChanged : function()
47866 this.items.each(function(f){
47867 if(f.hasChanged()){
47876 * Resets all hasChanged to 'false' -
47877 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47878 * So hasChanged storage is only to be used for this purpose
47881 resetHasChanged : function()
47883 this.items.each(function(f){
47884 f.resetHasChanged();
47891 * Performs a predefined action (submit or load) or custom actions you define on this form.
47892 * @param {String} actionName The name of the action type
47893 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47894 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47895 * accept other config options):
47897 Property Type Description
47898 ---------------- --------------- ----------------------------------------------------------------------------------
47899 url String The url for the action (defaults to the form's url)
47900 method String The form method to use (defaults to the form's method, or POST if not defined)
47901 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47902 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47903 validate the form on the client (defaults to false)
47905 * @return {BasicForm} this
47907 doAction : function(action, options){
47908 if(typeof action == 'string'){
47909 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47911 if(this.fireEvent('beforeaction', this, action) !== false){
47912 this.beforeAction(action);
47913 action.run.defer(100, action);
47919 * Shortcut to do a submit action.
47920 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47921 * @return {BasicForm} this
47923 submit : function(options){
47924 this.doAction('submit', options);
47929 * Shortcut to do a load action.
47930 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47931 * @return {BasicForm} this
47933 load : function(options){
47934 this.doAction('load', options);
47939 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47940 * @param {Record} record The record to edit
47941 * @return {BasicForm} this
47943 updateRecord : function(record){
47944 record.beginEdit();
47945 var fs = record.fields;
47946 fs.each(function(f){
47947 var field = this.findField(f.name);
47949 record.set(f.name, field.getValue());
47957 * Loads an Roo.data.Record into this form.
47958 * @param {Record} record The record to load
47959 * @return {BasicForm} this
47961 loadRecord : function(record){
47962 this.setValues(record.data);
47967 beforeAction : function(action){
47968 var o = action.options;
47970 if(!this.disableMask) {
47971 if(this.waitMsgTarget === true){
47972 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47973 }else if(this.waitMsgTarget){
47974 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47975 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47977 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47985 afterAction : function(action, success){
47986 this.activeAction = null;
47987 var o = action.options;
47989 if(!this.disableMask) {
47990 if(this.waitMsgTarget === true){
47992 }else if(this.waitMsgTarget){
47993 this.waitMsgTarget.unmask();
47995 Roo.MessageBox.updateProgress(1);
47996 Roo.MessageBox.hide();
48004 Roo.callback(o.success, o.scope, [this, action]);
48005 this.fireEvent('actioncomplete', this, action);
48009 // failure condition..
48010 // we have a scenario where updates need confirming.
48011 // eg. if a locking scenario exists..
48012 // we look for { errors : { needs_confirm : true }} in the response.
48014 (typeof(action.result) != 'undefined') &&
48015 (typeof(action.result.errors) != 'undefined') &&
48016 (typeof(action.result.errors.needs_confirm) != 'undefined')
48019 Roo.MessageBox.confirm(
48020 "Change requires confirmation",
48021 action.result.errorMsg,
48026 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
48036 Roo.callback(o.failure, o.scope, [this, action]);
48037 // show an error message if no failed handler is set..
48038 if (!this.hasListener('actionfailed')) {
48039 Roo.MessageBox.alert("Error",
48040 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
48041 action.result.errorMsg :
48042 "Saving Failed, please check your entries or try again"
48046 this.fireEvent('actionfailed', this, action);
48052 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
48053 * @param {String} id The value to search for
48056 findField : function(id){
48057 var field = this.items.get(id);
48059 this.items.each(function(f){
48060 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
48066 return field || null;
48070 * Add a secondary form to this one,
48071 * Used to provide tabbed forms. One form is primary, with hidden values
48072 * which mirror the elements from the other forms.
48074 * @param {Roo.form.Form} form to add.
48077 addForm : function(form)
48080 if (this.childForms.indexOf(form) > -1) {
48084 this.childForms.push(form);
48086 Roo.each(form.allItems, function (fe) {
48088 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
48089 if (this.findField(n)) { // already added..
48092 var add = new Roo.form.Hidden({
48095 add.render(this.el);
48102 * Mark fields in this form invalid in bulk.
48103 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
48104 * @return {BasicForm} this
48106 markInvalid : function(errors){
48107 if(errors instanceof Array){
48108 for(var i = 0, len = errors.length; i < len; i++){
48109 var fieldError = errors[i];
48110 var f = this.findField(fieldError.id);
48112 f.markInvalid(fieldError.msg);
48118 if(typeof errors[id] != 'function' && (field = this.findField(id))){
48119 field.markInvalid(errors[id]);
48123 Roo.each(this.childForms || [], function (f) {
48124 f.markInvalid(errors);
48131 * Set values for fields in this form in bulk.
48132 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
48133 * @return {BasicForm} this
48135 setValues : function(values){
48136 if(values instanceof Array){ // array of objects
48137 for(var i = 0, len = values.length; i < len; i++){
48139 var f = this.findField(v.id);
48141 f.setValue(v.value);
48142 if(this.trackResetOnLoad){
48143 f.originalValue = f.getValue();
48147 }else{ // object hash
48150 if(typeof values[id] != 'function' && (field = this.findField(id))){
48152 if (field.setFromData &&
48153 field.valueField &&
48154 field.displayField &&
48155 // combos' with local stores can
48156 // be queried via setValue()
48157 // to set their value..
48158 (field.store && !field.store.isLocal)
48162 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
48163 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
48164 field.setFromData(sd);
48167 field.setValue(values[id]);
48171 if(this.trackResetOnLoad){
48172 field.originalValue = field.getValue();
48177 this.resetHasChanged();
48180 Roo.each(this.childForms || [], function (f) {
48181 f.setValues(values);
48182 f.resetHasChanged();
48189 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
48190 * they are returned as an array.
48191 * @param {Boolean} asString
48194 getValues : function(asString){
48195 if (this.childForms) {
48196 // copy values from the child forms
48197 Roo.each(this.childForms, function (f) {
48198 this.setValues(f.getValues());
48203 if (typeof(FormData) != 'undefined' && asString !== true) {
48204 // this relies on a 'recent' version of chrome apparently...
48206 var fd = (new FormData(this.el.dom)).entries();
48208 var ent = fd.next();
48209 while (!ent.done) {
48210 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
48221 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
48222 if(asString === true){
48225 return Roo.urlDecode(fs);
48229 * Returns the fields in this form as an object with key/value pairs.
48230 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48233 getFieldValues : function(with_hidden)
48235 if (this.childForms) {
48236 // copy values from the child forms
48237 // should this call getFieldValues - probably not as we do not currently copy
48238 // hidden fields when we generate..
48239 Roo.each(this.childForms, function (f) {
48240 this.setValues(f.getValues());
48245 this.items.each(function(f){
48246 if (!f.getName()) {
48249 var v = f.getValue();
48250 if (f.inputType =='radio') {
48251 if (typeof(ret[f.getName()]) == 'undefined') {
48252 ret[f.getName()] = ''; // empty..
48255 if (!f.el.dom.checked) {
48259 v = f.el.dom.value;
48263 // not sure if this supported any more..
48264 if ((typeof(v) == 'object') && f.getRawValue) {
48265 v = f.getRawValue() ; // dates..
48267 // combo boxes where name != hiddenName...
48268 if (f.name != f.getName()) {
48269 ret[f.name] = f.getRawValue();
48271 ret[f.getName()] = v;
48278 * Clears all invalid messages in this form.
48279 * @return {BasicForm} this
48281 clearInvalid : function(){
48282 this.items.each(function(f){
48286 Roo.each(this.childForms || [], function (f) {
48295 * Resets this form.
48296 * @return {BasicForm} this
48298 reset : function(){
48299 this.items.each(function(f){
48303 Roo.each(this.childForms || [], function (f) {
48306 this.resetHasChanged();
48312 * Add Roo.form components to this form.
48313 * @param {Field} field1
48314 * @param {Field} field2 (optional)
48315 * @param {Field} etc (optional)
48316 * @return {BasicForm} this
48319 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48325 * Removes a field from the items collection (does NOT remove its markup).
48326 * @param {Field} field
48327 * @return {BasicForm} this
48329 remove : function(field){
48330 this.items.remove(field);
48335 * Looks at the fields in this form, checks them for an id attribute,
48336 * and calls applyTo on the existing dom element with that id.
48337 * @return {BasicForm} this
48339 render : function(){
48340 this.items.each(function(f){
48341 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48349 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48350 * @param {Object} values
48351 * @return {BasicForm} this
48353 applyToFields : function(o){
48354 this.items.each(function(f){
48361 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48362 * @param {Object} values
48363 * @return {BasicForm} this
48365 applyIfToFields : function(o){
48366 this.items.each(function(f){
48374 Roo.BasicForm = Roo.form.BasicForm;
48376 Roo.apply(Roo.form.BasicForm, {
48390 intervalID : false,
48396 if(this.isApplied){
48401 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48402 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48403 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48404 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48407 this.maskEl.top.enableDisplayMode("block");
48408 this.maskEl.left.enableDisplayMode("block");
48409 this.maskEl.bottom.enableDisplayMode("block");
48410 this.maskEl.right.enableDisplayMode("block");
48412 Roo.get(document.body).on('click', function(){
48416 Roo.get(document.body).on('touchstart', function(){
48420 this.isApplied = true
48423 mask : function(form, target)
48427 this.target = target;
48429 if(!this.form.errorMask || !target.el){
48433 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48435 var ot = this.target.el.calcOffsetsTo(scrollable);
48437 var scrollTo = ot[1] - this.form.maskOffset;
48439 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48441 scrollable.scrollTo('top', scrollTo);
48443 var el = this.target.wrap || this.target.el;
48445 var box = el.getBox();
48447 this.maskEl.top.setStyle('position', 'absolute');
48448 this.maskEl.top.setStyle('z-index', 10000);
48449 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48450 this.maskEl.top.setLeft(0);
48451 this.maskEl.top.setTop(0);
48452 this.maskEl.top.show();
48454 this.maskEl.left.setStyle('position', 'absolute');
48455 this.maskEl.left.setStyle('z-index', 10000);
48456 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48457 this.maskEl.left.setLeft(0);
48458 this.maskEl.left.setTop(box.y - this.padding);
48459 this.maskEl.left.show();
48461 this.maskEl.bottom.setStyle('position', 'absolute');
48462 this.maskEl.bottom.setStyle('z-index', 10000);
48463 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48464 this.maskEl.bottom.setLeft(0);
48465 this.maskEl.bottom.setTop(box.bottom + this.padding);
48466 this.maskEl.bottom.show();
48468 this.maskEl.right.setStyle('position', 'absolute');
48469 this.maskEl.right.setStyle('z-index', 10000);
48470 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48471 this.maskEl.right.setLeft(box.right + this.padding);
48472 this.maskEl.right.setTop(box.y - this.padding);
48473 this.maskEl.right.show();
48475 this.intervalID = window.setInterval(function() {
48476 Roo.form.BasicForm.popover.unmask();
48479 window.onwheel = function(){ return false;};
48481 (function(){ this.isMasked = true; }).defer(500, this);
48485 unmask : function()
48487 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48491 this.maskEl.top.setStyle('position', 'absolute');
48492 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48493 this.maskEl.top.hide();
48495 this.maskEl.left.setStyle('position', 'absolute');
48496 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48497 this.maskEl.left.hide();
48499 this.maskEl.bottom.setStyle('position', 'absolute');
48500 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48501 this.maskEl.bottom.hide();
48503 this.maskEl.right.setStyle('position', 'absolute');
48504 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48505 this.maskEl.right.hide();
48507 window.onwheel = function(){ return true;};
48509 if(this.intervalID){
48510 window.clearInterval(this.intervalID);
48511 this.intervalID = false;
48514 this.isMasked = false;
48522 * Ext JS Library 1.1.1
48523 * Copyright(c) 2006-2007, Ext JS, LLC.
48525 * Originally Released Under LGPL - original licence link has changed is not relivant.
48528 * <script type="text/javascript">
48532 * @class Roo.form.Form
48533 * @extends Roo.form.BasicForm
48534 * @children Roo.form.Column Roo.form.FieldSet Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
48535 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48537 * @param {Object} config Configuration options
48539 Roo.form.Form = function(config){
48541 if (config.items) {
48542 xitems = config.items;
48543 delete config.items;
48547 Roo.form.Form.superclass.constructor.call(this, null, config);
48548 this.url = this.url || this.action;
48550 this.root = new Roo.form.Layout(Roo.applyIf({
48554 this.active = this.root;
48556 * Array of all the buttons that have been added to this form via {@link addButton}
48560 this.allItems = [];
48563 * @event clientvalidation
48564 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48565 * @param {Form} this
48566 * @param {Boolean} valid true if the form has passed client-side validation
48568 clientvalidation: true,
48571 * Fires when the form is rendered
48572 * @param {Roo.form.Form} form
48577 if (this.progressUrl) {
48578 // push a hidden field onto the list of fields..
48582 name : 'UPLOAD_IDENTIFIER'
48587 Roo.each(xitems, this.addxtype, this);
48591 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48593 * @cfg {Roo.Button} buttons[] buttons at bottom of form
48597 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48600 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48603 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48605 buttonAlign:'center',
48608 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48613 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48614 * This property cascades to child containers if not set.
48619 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48620 * fires a looping event with that state. This is required to bind buttons to the valid
48621 * state using the config value formBind:true on the button.
48623 monitorValid : false,
48626 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48631 * @cfg {String} progressUrl - Url to return progress data
48634 progressUrl : false,
48636 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48637 * sending a formdata with extra parameters - eg uploaded elements.
48643 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48644 * fields are added and the column is closed. If no fields are passed the column remains open
48645 * until end() is called.
48646 * @param {Object} config The config to pass to the column
48647 * @param {Field} field1 (optional)
48648 * @param {Field} field2 (optional)
48649 * @param {Field} etc (optional)
48650 * @return Column The column container object
48652 column : function(c){
48653 var col = new Roo.form.Column(c);
48655 if(arguments.length > 1){ // duplicate code required because of Opera
48656 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48663 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48664 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48665 * until end() is called.
48666 * @param {Object} config The config to pass to the fieldset
48667 * @param {Field} field1 (optional)
48668 * @param {Field} field2 (optional)
48669 * @param {Field} etc (optional)
48670 * @return FieldSet The fieldset container object
48672 fieldset : function(c){
48673 var fs = new Roo.form.FieldSet(c);
48675 if(arguments.length > 1){ // duplicate code required because of Opera
48676 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48683 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48684 * fields are added and the container is closed. If no fields are passed the container remains open
48685 * until end() is called.
48686 * @param {Object} config The config to pass to the Layout
48687 * @param {Field} field1 (optional)
48688 * @param {Field} field2 (optional)
48689 * @param {Field} etc (optional)
48690 * @return Layout The container object
48692 container : function(c){
48693 var l = new Roo.form.Layout(c);
48695 if(arguments.length > 1){ // duplicate code required because of Opera
48696 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48703 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48704 * @param {Object} container A Roo.form.Layout or subclass of Layout
48705 * @return {Form} this
48707 start : function(c){
48708 // cascade label info
48709 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48710 this.active.stack.push(c);
48711 c.ownerCt = this.active;
48717 * Closes the current open container
48718 * @return {Form} this
48721 if(this.active == this.root){
48724 this.active = this.active.ownerCt;
48729 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48730 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48731 * as the label of the field.
48732 * @param {Field} field1
48733 * @param {Field} field2 (optional)
48734 * @param {Field} etc. (optional)
48735 * @return {Form} this
48738 this.active.stack.push.apply(this.active.stack, arguments);
48739 this.allItems.push.apply(this.allItems,arguments);
48741 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48742 if(a[i].isFormField){
48747 Roo.form.Form.superclass.add.apply(this, r);
48757 * Find any element that has been added to a form, using it's ID or name
48758 * This can include framesets, columns etc. along with regular fields..
48759 * @param {String} id - id or name to find.
48761 * @return {Element} e - or false if nothing found.
48763 findbyId : function(id)
48769 Roo.each(this.allItems, function(f){
48770 if (f.id == id || f.name == id ){
48781 * Render this form into the passed container. This should only be called once!
48782 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48783 * @return {Form} this
48785 render : function(ct)
48791 var o = this.autoCreate || {
48793 method : this.method || 'POST',
48794 id : this.id || Roo.id()
48796 this.initEl(ct.createChild(o));
48798 this.root.render(this.el);
48802 this.items.each(function(f){
48803 f.render('x-form-el-'+f.id);
48806 if(this.buttons.length > 0){
48807 // tables are required to maintain order and for correct IE layout
48808 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48809 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48810 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48812 var tr = tb.getElementsByTagName('tr')[0];
48813 for(var i = 0, len = this.buttons.length; i < len; i++) {
48814 var b = this.buttons[i];
48815 var td = document.createElement('td');
48816 td.className = 'x-form-btn-td';
48817 b.render(tr.appendChild(td));
48820 if(this.monitorValid){ // initialize after render
48821 this.startMonitoring();
48823 this.fireEvent('rendered', this);
48828 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48829 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48830 * object or a valid Roo.DomHelper element config
48831 * @param {Function} handler The function called when the button is clicked
48832 * @param {Object} scope (optional) The scope of the handler function
48833 * @return {Roo.Button}
48835 addButton : function(config, handler, scope){
48839 minWidth: this.minButtonWidth,
48842 if(typeof config == "string"){
48845 Roo.apply(bc, config);
48847 var btn = new Roo.Button(null, bc);
48848 this.buttons.push(btn);
48853 * Adds a series of form elements (using the xtype property as the factory method.
48854 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48855 * @param {Object} config
48858 addxtype : function()
48860 var ar = Array.prototype.slice.call(arguments, 0);
48862 for(var i = 0; i < ar.length; i++) {
48864 continue; // skip -- if this happends something invalid got sent, we
48865 // should ignore it, as basically that interface element will not show up
48866 // and that should be pretty obvious!!
48869 if (Roo.form[ar[i].xtype]) {
48871 var fe = Roo.factory(ar[i], Roo.form);
48877 fe.store.form = this;
48882 this.allItems.push(fe);
48883 if (fe.items && fe.addxtype) {
48884 fe.addxtype.apply(fe, fe.items);
48894 // console.log('adding ' + ar[i].xtype);
48896 if (ar[i].xtype == 'Button') {
48897 //console.log('adding button');
48898 //console.log(ar[i]);
48899 this.addButton(ar[i]);
48900 this.allItems.push(fe);
48904 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48905 alert('end is not supported on xtype any more, use items');
48907 // //console.log('adding end');
48915 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48916 * option "monitorValid"
48918 startMonitoring : function(){
48921 Roo.TaskMgr.start({
48922 run : this.bindHandler,
48923 interval : this.monitorPoll || 200,
48930 * Stops monitoring of the valid state of this form
48932 stopMonitoring : function(){
48933 this.bound = false;
48937 bindHandler : function(){
48939 return false; // stops binding
48942 this.items.each(function(f){
48943 if(!f.isValid(true)){
48948 for(var i = 0, len = this.buttons.length; i < len; i++){
48949 var btn = this.buttons[i];
48950 if(btn.formBind === true && btn.disabled === valid){
48951 btn.setDisabled(!valid);
48954 this.fireEvent('clientvalidation', this, valid);
48968 Roo.Form = Roo.form.Form;
48971 * Ext JS Library 1.1.1
48972 * Copyright(c) 2006-2007, Ext JS, LLC.
48974 * Originally Released Under LGPL - original licence link has changed is not relivant.
48977 * <script type="text/javascript">
48980 // as we use this in bootstrap.
48981 Roo.namespace('Roo.form');
48983 * @class Roo.form.Action
48984 * Internal Class used to handle form actions
48986 * @param {Roo.form.BasicForm} el The form element or its id
48987 * @param {Object} config Configuration options
48992 // define the action interface
48993 Roo.form.Action = function(form, options){
48995 this.options = options || {};
48998 * Client Validation Failed
49001 Roo.form.Action.CLIENT_INVALID = 'client';
49003 * Server Validation Failed
49006 Roo.form.Action.SERVER_INVALID = 'server';
49008 * Connect to Server Failed
49011 Roo.form.Action.CONNECT_FAILURE = 'connect';
49013 * Reading Data from Server Failed
49016 Roo.form.Action.LOAD_FAILURE = 'load';
49018 Roo.form.Action.prototype = {
49020 failureType : undefined,
49021 response : undefined,
49022 result : undefined,
49024 // interface method
49025 run : function(options){
49029 // interface method
49030 success : function(response){
49034 // interface method
49035 handleResponse : function(response){
49039 // default connection failure
49040 failure : function(response){
49042 this.response = response;
49043 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49044 this.form.afterAction(this, false);
49047 processResponse : function(response){
49048 this.response = response;
49049 if(!response.responseText){
49052 this.result = this.handleResponse(response);
49053 return this.result;
49056 // utility functions used internally
49057 getUrl : function(appendParams){
49058 var url = this.options.url || this.form.url || this.form.el.dom.action;
49060 var p = this.getParams();
49062 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
49068 getMethod : function(){
49069 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
49072 getParams : function(){
49073 var bp = this.form.baseParams;
49074 var p = this.options.params;
49076 if(typeof p == "object"){
49077 p = Roo.urlEncode(Roo.applyIf(p, bp));
49078 }else if(typeof p == 'string' && bp){
49079 p += '&' + Roo.urlEncode(bp);
49082 p = Roo.urlEncode(bp);
49087 createCallback : function(){
49089 success: this.success,
49090 failure: this.failure,
49092 timeout: (this.form.timeout*1000),
49093 upload: this.form.fileUpload ? this.success : undefined
49098 Roo.form.Action.Submit = function(form, options){
49099 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
49102 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
49105 haveProgress : false,
49106 uploadComplete : false,
49108 // uploadProgress indicator.
49109 uploadProgress : function()
49111 if (!this.form.progressUrl) {
49115 if (!this.haveProgress) {
49116 Roo.MessageBox.progress("Uploading", "Uploading");
49118 if (this.uploadComplete) {
49119 Roo.MessageBox.hide();
49123 this.haveProgress = true;
49125 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
49127 var c = new Roo.data.Connection();
49129 url : this.form.progressUrl,
49134 success : function(req){
49135 //console.log(data);
49139 rdata = Roo.decode(req.responseText)
49141 Roo.log("Invalid data from server..");
49145 if (!rdata || !rdata.success) {
49147 Roo.MessageBox.alert(Roo.encode(rdata));
49150 var data = rdata.data;
49152 if (this.uploadComplete) {
49153 Roo.MessageBox.hide();
49158 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
49159 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
49162 this.uploadProgress.defer(2000,this);
49165 failure: function(data) {
49166 Roo.log('progress url failed ');
49177 // run get Values on the form, so it syncs any secondary forms.
49178 this.form.getValues();
49180 var o = this.options;
49181 var method = this.getMethod();
49182 var isPost = method == 'POST';
49183 if(o.clientValidation === false || this.form.isValid()){
49185 if (this.form.progressUrl) {
49186 this.form.findField('UPLOAD_IDENTIFIER').setValue(
49187 (new Date() * 1) + '' + Math.random());
49192 Roo.Ajax.request(Roo.apply(this.createCallback(), {
49193 form:this.form.el.dom,
49194 url:this.getUrl(!isPost),
49196 params:isPost ? this.getParams() : null,
49197 isUpload: this.form.fileUpload,
49198 formData : this.form.formData
49201 this.uploadProgress();
49203 }else if (o.clientValidation !== false){ // client validation failed
49204 this.failureType = Roo.form.Action.CLIENT_INVALID;
49205 this.form.afterAction(this, false);
49209 success : function(response)
49211 this.uploadComplete= true;
49212 if (this.haveProgress) {
49213 Roo.MessageBox.hide();
49217 var result = this.processResponse(response);
49218 if(result === true || result.success){
49219 this.form.afterAction(this, true);
49223 this.form.markInvalid(result.errors);
49224 this.failureType = Roo.form.Action.SERVER_INVALID;
49226 this.form.afterAction(this, false);
49228 failure : function(response)
49230 this.uploadComplete= true;
49231 if (this.haveProgress) {
49232 Roo.MessageBox.hide();
49235 this.response = response;
49236 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49237 this.form.afterAction(this, false);
49240 handleResponse : function(response){
49241 if(this.form.errorReader){
49242 var rs = this.form.errorReader.read(response);
49245 for(var i = 0, len = rs.records.length; i < len; i++) {
49246 var r = rs.records[i];
49247 errors[i] = r.data;
49250 if(errors.length < 1){
49254 success : rs.success,
49260 ret = Roo.decode(response.responseText);
49264 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49274 Roo.form.Action.Load = function(form, options){
49275 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49276 this.reader = this.form.reader;
49279 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49284 Roo.Ajax.request(Roo.apply(
49285 this.createCallback(), {
49286 method:this.getMethod(),
49287 url:this.getUrl(false),
49288 params:this.getParams()
49292 success : function(response){
49294 var result = this.processResponse(response);
49295 if(result === true || !result.success || !result.data){
49296 this.failureType = Roo.form.Action.LOAD_FAILURE;
49297 this.form.afterAction(this, false);
49300 this.form.clearInvalid();
49301 this.form.setValues(result.data);
49302 this.form.afterAction(this, true);
49305 handleResponse : function(response){
49306 if(this.form.reader){
49307 var rs = this.form.reader.read(response);
49308 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49310 success : rs.success,
49314 return Roo.decode(response.responseText);
49318 Roo.form.Action.ACTION_TYPES = {
49319 'load' : Roo.form.Action.Load,
49320 'submit' : Roo.form.Action.Submit
49323 * Ext JS Library 1.1.1
49324 * Copyright(c) 2006-2007, Ext JS, LLC.
49326 * Originally Released Under LGPL - original licence link has changed is not relivant.
49329 * <script type="text/javascript">
49333 * @class Roo.form.Layout
49334 * @extends Roo.Component
49335 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49336 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49338 * @param {Object} config Configuration options
49340 Roo.form.Layout = function(config){
49342 if (config.items) {
49343 xitems = config.items;
49344 delete config.items;
49346 Roo.form.Layout.superclass.constructor.call(this, config);
49348 Roo.each(xitems, this.addxtype, this);
49352 Roo.extend(Roo.form.Layout, Roo.Component, {
49354 * @cfg {String/Object} autoCreate
49355 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49358 * @cfg {String/Object/Function} style
49359 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49360 * a function which returns such a specification.
49363 * @cfg {String} labelAlign
49364 * Valid values are "left," "top" and "right" (defaults to "left")
49367 * @cfg {Number} labelWidth
49368 * Fixed width in pixels of all field labels (defaults to undefined)
49371 * @cfg {Boolean} clear
49372 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49376 * @cfg {String} labelSeparator
49377 * The separator to use after field labels (defaults to ':')
49379 labelSeparator : ':',
49381 * @cfg {Boolean} hideLabels
49382 * True to suppress the display of field labels in this layout (defaults to false)
49384 hideLabels : false,
49387 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49392 onRender : function(ct, position){
49393 if(this.el){ // from markup
49394 this.el = Roo.get(this.el);
49395 }else { // generate
49396 var cfg = this.getAutoCreate();
49397 this.el = ct.createChild(cfg, position);
49400 this.el.applyStyles(this.style);
49402 if(this.labelAlign){
49403 this.el.addClass('x-form-label-'+this.labelAlign);
49405 if(this.hideLabels){
49406 this.labelStyle = "display:none";
49407 this.elementStyle = "padding-left:0;";
49409 if(typeof this.labelWidth == 'number'){
49410 this.labelStyle = "width:"+this.labelWidth+"px;";
49411 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49413 if(this.labelAlign == 'top'){
49414 this.labelStyle = "width:auto;";
49415 this.elementStyle = "padding-left:0;";
49418 var stack = this.stack;
49419 var slen = stack.length;
49421 if(!this.fieldTpl){
49422 var t = new Roo.Template(
49423 '<div class="x-form-item {5}">',
49424 '<label for="{0}" style="{2}">{1}{4}</label>',
49425 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49427 '</div><div class="x-form-clear-left"></div>'
49429 t.disableFormats = true;
49431 Roo.form.Layout.prototype.fieldTpl = t;
49433 for(var i = 0; i < slen; i++) {
49434 if(stack[i].isFormField){
49435 this.renderField(stack[i]);
49437 this.renderComponent(stack[i]);
49442 this.el.createChild({cls:'x-form-clear'});
49447 renderField : function(f){
49448 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49451 f.labelStyle||this.labelStyle||'', //2
49452 this.elementStyle||'', //3
49453 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49454 f.itemCls||this.itemCls||'' //5
49455 ], true).getPrevSibling());
49459 renderComponent : function(c){
49460 c.render(c.isLayout ? this.el : this.el.createChild());
49463 * Adds a object form elements (using the xtype property as the factory method.)
49464 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49465 * @param {Object} config
49467 addxtype : function(o)
49469 // create the lement.
49470 o.form = this.form;
49471 var fe = Roo.factory(o, Roo.form);
49472 this.form.allItems.push(fe);
49473 this.stack.push(fe);
49475 if (fe.isFormField) {
49476 this.form.items.add(fe);
49484 * @class Roo.form.Column
49485 * @extends Roo.form.Layout
49486 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49488 * @param {Object} config Configuration options
49490 Roo.form.Column = function(config){
49491 Roo.form.Column.superclass.constructor.call(this, config);
49494 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49496 * @cfg {Number/String} width
49497 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49500 * @cfg {String/Object} autoCreate
49501 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49505 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49508 onRender : function(ct, position){
49509 Roo.form.Column.superclass.onRender.call(this, ct, position);
49511 this.el.setWidth(this.width);
49518 * @class Roo.form.Row
49519 * @extends Roo.form.Layout
49520 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49521 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49523 * @param {Object} config Configuration options
49527 Roo.form.Row = function(config){
49528 Roo.form.Row.superclass.constructor.call(this, config);
49531 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49533 * @cfg {Number/String} width
49534 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49537 * @cfg {Number/String} height
49538 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49540 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49544 onRender : function(ct, position){
49545 //console.log('row render');
49547 var t = new Roo.Template(
49548 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49549 '<label for="{0}" style="{2}">{1}{4}</label>',
49550 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49554 t.disableFormats = true;
49556 Roo.form.Layout.prototype.rowTpl = t;
49558 this.fieldTpl = this.rowTpl;
49560 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49561 var labelWidth = 100;
49563 if ((this.labelAlign != 'top')) {
49564 if (typeof this.labelWidth == 'number') {
49565 labelWidth = this.labelWidth
49567 this.padWidth = 20 + labelWidth;
49571 Roo.form.Column.superclass.onRender.call(this, ct, position);
49573 this.el.setWidth(this.width);
49576 this.el.setHeight(this.height);
49581 renderField : function(f){
49582 f.fieldEl = this.fieldTpl.append(this.el, [
49583 f.id, f.fieldLabel,
49584 f.labelStyle||this.labelStyle||'',
49585 this.elementStyle||'',
49586 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49587 f.itemCls||this.itemCls||'',
49588 f.width ? f.width + this.padWidth : 160 + this.padWidth
49595 * @class Roo.form.FieldSet
49596 * @extends Roo.form.Layout
49597 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49598 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49600 * @param {Object} config Configuration options
49602 Roo.form.FieldSet = function(config){
49603 Roo.form.FieldSet.superclass.constructor.call(this, config);
49606 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49608 * @cfg {String} legend
49609 * The text to display as the legend for the FieldSet (defaults to '')
49612 * @cfg {String/Object} autoCreate
49613 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49617 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49620 onRender : function(ct, position){
49621 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49623 this.setLegend(this.legend);
49628 setLegend : function(text){
49630 this.el.child('legend').update(text);
49635 * Ext JS Library 1.1.1
49636 * Copyright(c) 2006-2007, Ext JS, LLC.
49638 * Originally Released Under LGPL - original licence link has changed is not relivant.
49641 * <script type="text/javascript">
49644 * @class Roo.form.VTypes
49645 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49648 Roo.form.VTypes = function(){
49649 // closure these in so they are only created once.
49650 var alpha = /^[a-zA-Z_]+$/;
49651 var alphanum = /^[a-zA-Z0-9_]+$/;
49652 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49653 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49655 // All these messages and functions are configurable
49658 * The function used to validate email addresses
49659 * @param {String} value The email address
49661 'email' : function(v){
49662 return email.test(v);
49665 * The error text to display when the email validation function returns false
49668 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49670 * The keystroke filter mask to be applied on email input
49673 'emailMask' : /[a-z0-9_\.\-@]/i,
49676 * The function used to validate URLs
49677 * @param {String} value The URL
49679 'url' : function(v){
49680 return url.test(v);
49683 * The error text to display when the url validation function returns false
49686 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49689 * The function used to validate alpha values
49690 * @param {String} value The value
49692 'alpha' : function(v){
49693 return alpha.test(v);
49696 * The error text to display when the alpha validation function returns false
49699 'alphaText' : 'This field should only contain letters and _',
49701 * The keystroke filter mask to be applied on alpha input
49704 'alphaMask' : /[a-z_]/i,
49707 * The function used to validate alphanumeric values
49708 * @param {String} value The value
49710 'alphanum' : function(v){
49711 return alphanum.test(v);
49714 * The error text to display when the alphanumeric validation function returns false
49717 'alphanumText' : 'This field should only contain letters, numbers and _',
49719 * The keystroke filter mask to be applied on alphanumeric input
49722 'alphanumMask' : /[a-z0-9_]/i
49724 }();//<script type="text/javascript">
49727 * @class Roo.form.FCKeditor
49728 * @extends Roo.form.TextArea
49729 * Wrapper around the FCKEditor http://www.fckeditor.net
49731 * Creates a new FCKeditor
49732 * @param {Object} config Configuration options
49734 Roo.form.FCKeditor = function(config){
49735 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49738 * @event editorinit
49739 * Fired when the editor is initialized - you can add extra handlers here..
49740 * @param {FCKeditor} this
49741 * @param {Object} the FCK object.
49748 Roo.form.FCKeditor.editors = { };
49749 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49751 //defaultAutoCreate : {
49752 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49756 * @cfg {Object} fck options - see fck manual for details.
49761 * @cfg {Object} fck toolbar set (Basic or Default)
49763 toolbarSet : 'Basic',
49765 * @cfg {Object} fck BasePath
49767 basePath : '/fckeditor/',
49775 onRender : function(ct, position)
49778 this.defaultAutoCreate = {
49780 style:"width:300px;height:60px;",
49781 autocomplete: "new-password"
49784 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49787 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49788 if(this.preventScrollbars){
49789 this.el.setStyle("overflow", "hidden");
49791 this.el.setHeight(this.growMin);
49794 //console.log('onrender' + this.getId() );
49795 Roo.form.FCKeditor.editors[this.getId()] = this;
49798 this.replaceTextarea() ;
49802 getEditor : function() {
49803 return this.fckEditor;
49806 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49807 * @param {Mixed} value The value to set
49811 setValue : function(value)
49813 //console.log('setValue: ' + value);
49815 if(typeof(value) == 'undefined') { // not sure why this is happending...
49818 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49820 //if(!this.el || !this.getEditor()) {
49821 // this.value = value;
49822 //this.setValue.defer(100,this,[value]);
49826 if(!this.getEditor()) {
49830 this.getEditor().SetData(value);
49837 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49838 * @return {Mixed} value The field value
49840 getValue : function()
49843 if (this.frame && this.frame.dom.style.display == 'none') {
49844 return Roo.form.FCKeditor.superclass.getValue.call(this);
49847 if(!this.el || !this.getEditor()) {
49849 // this.getValue.defer(100,this);
49854 var value=this.getEditor().GetData();
49855 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49856 return Roo.form.FCKeditor.superclass.getValue.call(this);
49862 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49863 * @return {Mixed} value The field value
49865 getRawValue : function()
49867 if (this.frame && this.frame.dom.style.display == 'none') {
49868 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49871 if(!this.el || !this.getEditor()) {
49872 //this.getRawValue.defer(100,this);
49879 var value=this.getEditor().GetData();
49880 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49881 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49885 setSize : function(w,h) {
49889 //if (this.frame && this.frame.dom.style.display == 'none') {
49890 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49893 //if(!this.el || !this.getEditor()) {
49894 // this.setSize.defer(100,this, [w,h]);
49900 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49902 this.frame.dom.setAttribute('width', w);
49903 this.frame.dom.setAttribute('height', h);
49904 this.frame.setSize(w,h);
49908 toggleSourceEdit : function(value) {
49912 this.el.dom.style.display = value ? '' : 'none';
49913 this.frame.dom.style.display = value ? 'none' : '';
49918 focus: function(tag)
49920 if (this.frame.dom.style.display == 'none') {
49921 return Roo.form.FCKeditor.superclass.focus.call(this);
49923 if(!this.el || !this.getEditor()) {
49924 this.focus.defer(100,this, [tag]);
49931 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49932 this.getEditor().Focus();
49934 if (!this.getEditor().Selection.GetSelection()) {
49935 this.focus.defer(100,this, [tag]);
49940 var r = this.getEditor().EditorDocument.createRange();
49941 r.setStart(tgs[0],0);
49942 r.setEnd(tgs[0],0);
49943 this.getEditor().Selection.GetSelection().removeAllRanges();
49944 this.getEditor().Selection.GetSelection().addRange(r);
49945 this.getEditor().Focus();
49952 replaceTextarea : function()
49954 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49957 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49959 // We must check the elements firstly using the Id and then the name.
49960 var oTextarea = document.getElementById( this.getId() );
49962 var colElementsByName = document.getElementsByName( this.getId() ) ;
49964 oTextarea.style.display = 'none' ;
49966 if ( oTextarea.tabIndex ) {
49967 this.TabIndex = oTextarea.tabIndex ;
49970 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49971 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49972 this.frame = Roo.get(this.getId() + '___Frame')
49975 _getConfigHtml : function()
49979 for ( var o in this.fckconfig ) {
49980 sConfig += sConfig.length > 0 ? '&' : '';
49981 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49984 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49988 _getIFrameHtml : function()
49990 var sFile = 'fckeditor.html' ;
49991 /* no idea what this is about..
49994 if ( (/fcksource=true/i).test( window.top.location.search ) )
49995 sFile = 'fckeditor.original.html' ;
50000 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
50001 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
50004 var html = '<iframe id="' + this.getId() +
50005 '___Frame" src="' + sLink +
50006 '" width="' + this.width +
50007 '" height="' + this.height + '"' +
50008 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
50009 ' frameborder="0" scrolling="no"></iframe>' ;
50014 _insertHtmlBefore : function( html, element )
50016 if ( element.insertAdjacentHTML ) {
50018 element.insertAdjacentHTML( 'beforeBegin', html ) ;
50020 var oRange = document.createRange() ;
50021 oRange.setStartBefore( element ) ;
50022 var oFragment = oRange.createContextualFragment( html );
50023 element.parentNode.insertBefore( oFragment, element ) ;
50036 //Roo.reg('fckeditor', Roo.form.FCKeditor);
50038 function FCKeditor_OnComplete(editorInstance){
50039 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
50040 f.fckEditor = editorInstance;
50041 //console.log("loaded");
50042 f.fireEvent('editorinit', f, editorInstance);
50062 //<script type="text/javascript">
50064 * @class Roo.form.GridField
50065 * @extends Roo.form.Field
50066 * Embed a grid (or editable grid into a form)
50069 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
50071 * xgrid.store = Roo.data.Store
50072 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
50073 * xgrid.store.reader = Roo.data.JsonReader
50077 * Creates a new GridField
50078 * @param {Object} config Configuration options
50080 Roo.form.GridField = function(config){
50081 Roo.form.GridField.superclass.constructor.call(this, config);
50085 Roo.extend(Roo.form.GridField, Roo.form.Field, {
50087 * @cfg {Number} width - used to restrict width of grid..
50091 * @cfg {Number} height - used to restrict height of grid..
50095 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
50101 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50102 * {tag: "input", type: "checkbox", autocomplete: "off"})
50104 // defaultAutoCreate : { tag: 'div' },
50105 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
50107 * @cfg {String} addTitle Text to include for adding a title.
50111 onResize : function(){
50112 Roo.form.Field.superclass.onResize.apply(this, arguments);
50115 initEvents : function(){
50116 // Roo.form.Checkbox.superclass.initEvents.call(this);
50117 // has no events...
50122 getResizeEl : function(){
50126 getPositionEl : function(){
50131 onRender : function(ct, position){
50133 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
50134 var style = this.style;
50137 Roo.form.GridField.superclass.onRender.call(this, ct, position);
50138 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
50139 this.viewEl = this.wrap.createChild({ tag: 'div' });
50141 this.viewEl.applyStyles(style);
50144 this.viewEl.setWidth(this.width);
50147 this.viewEl.setHeight(this.height);
50149 //if(this.inputValue !== undefined){
50150 //this.setValue(this.value);
50153 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
50156 this.grid.render();
50157 this.grid.getDataSource().on('remove', this.refreshValue, this);
50158 this.grid.getDataSource().on('update', this.refreshValue, this);
50159 this.grid.on('afteredit', this.refreshValue, this);
50165 * Sets the value of the item.
50166 * @param {String} either an object or a string..
50168 setValue : function(v){
50170 v = v || []; // empty set..
50171 // this does not seem smart - it really only affects memoryproxy grids..
50172 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
50173 var ds = this.grid.getDataSource();
50174 // assumes a json reader..
50176 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
50177 ds.loadData( data);
50179 // clear selection so it does not get stale.
50180 if (this.grid.sm) {
50181 this.grid.sm.clearSelections();
50184 Roo.form.GridField.superclass.setValue.call(this, v);
50185 this.refreshValue();
50186 // should load data in the grid really....
50190 refreshValue: function() {
50192 this.grid.getDataSource().each(function(r) {
50195 this.el.dom.value = Roo.encode(val);
50203 * Ext JS Library 1.1.1
50204 * Copyright(c) 2006-2007, Ext JS, LLC.
50206 * Originally Released Under LGPL - original licence link has changed is not relivant.
50209 * <script type="text/javascript">
50212 * @class Roo.form.DisplayField
50213 * @extends Roo.form.Field
50214 * A generic Field to display non-editable data.
50215 * @cfg {Boolean} closable (true|false) default false
50217 * Creates a new Display Field item.
50218 * @param {Object} config Configuration options
50220 Roo.form.DisplayField = function(config){
50221 Roo.form.DisplayField.superclass.constructor.call(this, config);
50226 * Fires after the click the close btn
50227 * @param {Roo.form.DisplayField} this
50233 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50234 inputType: 'hidden',
50240 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50242 focusClass : undefined,
50244 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50246 fieldClass: 'x-form-field',
50249 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50251 valueRenderer: undefined,
50255 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50256 * {tag: "input", type: "checkbox", autocomplete: "off"})
50259 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50263 onResize : function(){
50264 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50268 initEvents : function(){
50269 // Roo.form.Checkbox.superclass.initEvents.call(this);
50270 // has no events...
50273 this.closeEl.on('click', this.onClose, this);
50279 getResizeEl : function(){
50283 getPositionEl : function(){
50288 onRender : function(ct, position){
50290 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50291 //if(this.inputValue !== undefined){
50292 this.wrap = this.el.wrap();
50294 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50297 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50300 if (this.bodyStyle) {
50301 this.viewEl.applyStyles(this.bodyStyle);
50303 //this.viewEl.setStyle('padding', '2px');
50305 this.setValue(this.value);
50310 initValue : Roo.emptyFn,
50315 onClick : function(){
50320 * Sets the checked state of the checkbox.
50321 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50323 setValue : function(v){
50325 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50326 // this might be called before we have a dom element..
50327 if (!this.viewEl) {
50330 this.viewEl.dom.innerHTML = html;
50331 Roo.form.DisplayField.superclass.setValue.call(this, v);
50335 onClose : function(e)
50337 e.preventDefault();
50339 this.fireEvent('close', this);
50348 * @class Roo.form.DayPicker
50349 * @extends Roo.form.Field
50350 * A Day picker show [M] [T] [W] ....
50352 * Creates a new Day Picker
50353 * @param {Object} config Configuration options
50355 Roo.form.DayPicker= function(config){
50356 Roo.form.DayPicker.superclass.constructor.call(this, config);
50360 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50362 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50364 focusClass : undefined,
50366 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50368 fieldClass: "x-form-field",
50371 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50372 * {tag: "input", type: "checkbox", autocomplete: "off"})
50374 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50377 actionMode : 'viewEl',
50381 inputType : 'hidden',
50384 inputElement: false, // real input element?
50385 basedOn: false, // ????
50387 isFormField: true, // not sure where this is needed!!!!
50389 onResize : function(){
50390 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50391 if(!this.boxLabel){
50392 this.el.alignTo(this.wrap, 'c-c');
50396 initEvents : function(){
50397 Roo.form.Checkbox.superclass.initEvents.call(this);
50398 this.el.on("click", this.onClick, this);
50399 this.el.on("change", this.onClick, this);
50403 getResizeEl : function(){
50407 getPositionEl : function(){
50413 onRender : function(ct, position){
50414 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50416 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50418 var r1 = '<table><tr>';
50419 var r2 = '<tr class="x-form-daypick-icons">';
50420 for (var i=0; i < 7; i++) {
50421 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50422 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50425 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50426 viewEl.select('img').on('click', this.onClick, this);
50427 this.viewEl = viewEl;
50430 // this will not work on Chrome!!!
50431 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50432 this.el.on('propertychange', this.setFromHidden, this); //ie
50440 initValue : Roo.emptyFn,
50443 * Returns the checked state of the checkbox.
50444 * @return {Boolean} True if checked, else false
50446 getValue : function(){
50447 return this.el.dom.value;
50452 onClick : function(e){
50453 //this.setChecked(!this.checked);
50454 Roo.get(e.target).toggleClass('x-menu-item-checked');
50455 this.refreshValue();
50456 //if(this.el.dom.checked != this.checked){
50457 // this.setValue(this.el.dom.checked);
50462 refreshValue : function()
50465 this.viewEl.select('img',true).each(function(e,i,n) {
50466 val += e.is(".x-menu-item-checked") ? String(n) : '';
50468 this.setValue(val, true);
50472 * Sets the checked state of the checkbox.
50473 * On is always based on a string comparison between inputValue and the param.
50474 * @param {Boolean/String} value - the value to set
50475 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50477 setValue : function(v,suppressEvent){
50478 if (!this.el.dom) {
50481 var old = this.el.dom.value ;
50482 this.el.dom.value = v;
50483 if (suppressEvent) {
50487 // update display..
50488 this.viewEl.select('img',true).each(function(e,i,n) {
50490 var on = e.is(".x-menu-item-checked");
50491 var newv = v.indexOf(String(n)) > -1;
50493 e.toggleClass('x-menu-item-checked');
50499 this.fireEvent('change', this, v, old);
50504 // handle setting of hidden value by some other method!!?!?
50505 setFromHidden: function()
50510 //console.log("SET FROM HIDDEN");
50511 //alert('setFrom hidden');
50512 this.setValue(this.el.dom.value);
50515 onDestroy : function()
50518 Roo.get(this.viewEl).remove();
50521 Roo.form.DayPicker.superclass.onDestroy.call(this);
50525 * RooJS Library 1.1.1
50526 * Copyright(c) 2008-2011 Alan Knowles
50533 * @class Roo.form.ComboCheck
50534 * @extends Roo.form.ComboBox
50535 * A combobox for multiple select items.
50537 * FIXME - could do with a reset button..
50540 * Create a new ComboCheck
50541 * @param {Object} config Configuration options
50543 Roo.form.ComboCheck = function(config){
50544 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50545 // should verify some data...
50547 // hiddenName = required..
50548 // displayField = required
50549 // valudField == required
50550 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50552 Roo.each(req, function(e) {
50553 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50554 throw "Roo.form.ComboCheck : missing value for: " + e;
50561 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50566 selectedClass: 'x-menu-item-checked',
50569 onRender : function(ct, position){
50575 var cls = 'x-combo-list';
50578 this.tpl = new Roo.Template({
50579 html : '<div class="'+cls+'-item x-menu-check-item">' +
50580 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50581 '<span>{' + this.displayField + '}</span>' +
50588 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50589 this.view.singleSelect = false;
50590 this.view.multiSelect = true;
50591 this.view.toggleSelect = true;
50592 this.pageTb.add(new Roo.Toolbar.Fill(), {
50595 handler: function()
50602 onViewOver : function(e, t){
50608 onViewClick : function(doFocus,index){
50612 select: function () {
50613 //Roo.log("SELECT CALLED");
50616 selectByValue : function(xv, scrollIntoView){
50617 var ar = this.getValueArray();
50620 Roo.each(ar, function(v) {
50621 if(v === undefined || v === null){
50624 var r = this.findRecord(this.valueField, v);
50626 sels.push(this.store.indexOf(r))
50630 this.view.select(sels);
50636 onSelect : function(record, index){
50637 // Roo.log("onselect Called");
50638 // this is only called by the clear button now..
50639 this.view.clearSelections();
50640 this.setValue('[]');
50641 if (this.value != this.valueBefore) {
50642 this.fireEvent('change', this, this.value, this.valueBefore);
50643 this.valueBefore = this.value;
50646 getValueArray : function()
50651 //Roo.log(this.value);
50652 if (typeof(this.value) == 'undefined') {
50655 var ar = Roo.decode(this.value);
50656 return ar instanceof Array ? ar : []; //?? valid?
50659 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50664 expand : function ()
50667 Roo.form.ComboCheck.superclass.expand.call(this);
50668 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50669 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50674 collapse : function(){
50675 Roo.form.ComboCheck.superclass.collapse.call(this);
50676 var sl = this.view.getSelectedIndexes();
50677 var st = this.store;
50681 Roo.each(sl, function(i) {
50683 nv.push(r.get(this.valueField));
50685 this.setValue(Roo.encode(nv));
50686 if (this.value != this.valueBefore) {
50688 this.fireEvent('change', this, this.value, this.valueBefore);
50689 this.valueBefore = this.value;
50694 setValue : function(v){
50698 var vals = this.getValueArray();
50700 Roo.each(vals, function(k) {
50701 var r = this.findRecord(this.valueField, k);
50703 tv.push(r.data[this.displayField]);
50704 }else if(this.valueNotFoundText !== undefined){
50705 tv.push( this.valueNotFoundText );
50710 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50711 this.hiddenField.value = v;
50717 * Ext JS Library 1.1.1
50718 * Copyright(c) 2006-2007, Ext JS, LLC.
50720 * Originally Released Under LGPL - original licence link has changed is not relivant.
50723 * <script type="text/javascript">
50727 * @class Roo.form.Signature
50728 * @extends Roo.form.Field
50732 * @param {Object} config Configuration options
50735 Roo.form.Signature = function(config){
50736 Roo.form.Signature.superclass.constructor.call(this, config);
50738 this.addEvents({// not in used??
50741 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50742 * @param {Roo.form.Signature} combo This combo box
50747 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50748 * @param {Roo.form.ComboBox} combo This combo box
50749 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50755 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50757 * @cfg {Object} labels Label to use when rendering a form.
50761 * confirm : "Confirm"
50766 confirm : "Confirm"
50769 * @cfg {Number} width The signature panel width (defaults to 300)
50773 * @cfg {Number} height The signature panel height (defaults to 100)
50777 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50779 allowBlank : false,
50782 // {Object} signPanel The signature SVG panel element (defaults to {})
50784 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50785 isMouseDown : false,
50786 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50787 isConfirmed : false,
50788 // {String} signatureTmp SVG mapping string (defaults to empty string)
50792 defaultAutoCreate : { // modified by initCompnoent..
50798 onRender : function(ct, position){
50800 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50802 this.wrap = this.el.wrap({
50803 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50806 this.createToolbar(this);
50807 this.signPanel = this.wrap.createChild({
50809 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50813 this.svgID = Roo.id();
50814 this.svgEl = this.signPanel.createChild({
50815 xmlns : 'http://www.w3.org/2000/svg',
50817 id : this.svgID + "-svg",
50819 height: this.height,
50820 viewBox: '0 0 '+this.width+' '+this.height,
50824 id: this.svgID + "-svg-r",
50826 height: this.height,
50831 id: this.svgID + "-svg-l",
50833 y1: (this.height*0.8), // start set the line in 80% of height
50834 x2: this.width, // end
50835 y2: (this.height*0.8), // end set the line in 80% of height
50837 'stroke-width': "1",
50838 'stroke-dasharray': "3",
50839 'shape-rendering': "crispEdges",
50840 'pointer-events': "none"
50844 id: this.svgID + "-svg-p",
50846 'stroke-width': "3",
50848 'pointer-events': 'none'
50853 this.svgBox = this.svgEl.dom.getScreenCTM();
50855 createSVG : function(){
50856 var svg = this.signPanel;
50857 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50860 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50861 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50862 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50863 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50864 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50865 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50866 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50869 isTouchEvent : function(e){
50870 return e.type.match(/^touch/);
50872 getCoords : function (e) {
50873 var pt = this.svgEl.dom.createSVGPoint();
50876 if (this.isTouchEvent(e)) {
50877 pt.x = e.targetTouches[0].clientX;
50878 pt.y = e.targetTouches[0].clientY;
50880 var a = this.svgEl.dom.getScreenCTM();
50881 var b = a.inverse();
50882 var mx = pt.matrixTransform(b);
50883 return mx.x + ',' + mx.y;
50885 //mouse event headler
50886 down : function (e) {
50887 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50888 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50890 this.isMouseDown = true;
50892 e.preventDefault();
50894 move : function (e) {
50895 if (this.isMouseDown) {
50896 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50897 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50900 e.preventDefault();
50902 up : function (e) {
50903 this.isMouseDown = false;
50904 var sp = this.signatureTmp.split(' ');
50907 if(!sp[sp.length-2].match(/^L/)){
50911 this.signatureTmp = sp.join(" ");
50914 if(this.getValue() != this.signatureTmp){
50915 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50916 this.isConfirmed = false;
50918 e.preventDefault();
50922 * Protected method that will not generally be called directly. It
50923 * is called when the editor creates its toolbar. Override this method if you need to
50924 * add custom toolbar buttons.
50925 * @param {HtmlEditor} editor
50927 createToolbar : function(editor){
50928 function btn(id, toggle, handler){
50929 var xid = fid + '-'+ id ;
50933 cls : 'x-btn-icon x-edit-'+id,
50934 enableToggle:toggle !== false,
50935 scope: editor, // was editor...
50936 handler:handler||editor.relayBtnCmd,
50937 clickEvent:'mousedown',
50938 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50944 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50948 cls : ' x-signature-btn x-signature-'+id,
50949 scope: editor, // was editor...
50950 handler: this.reset,
50951 clickEvent:'mousedown',
50952 text: this.labels.clear
50959 cls : ' x-signature-btn x-signature-'+id,
50960 scope: editor, // was editor...
50961 handler: this.confirmHandler,
50962 clickEvent:'mousedown',
50963 text: this.labels.confirm
50970 * when user is clicked confirm then show this image.....
50972 * @return {String} Image Data URI
50974 getImageDataURI : function(){
50975 var svg = this.svgEl.dom.parentNode.innerHTML;
50976 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50981 * @return {Boolean} this.isConfirmed
50983 getConfirmed : function(){
50984 return this.isConfirmed;
50988 * @return {Number} this.width
50990 getWidth : function(){
50995 * @return {Number} this.height
50997 getHeight : function(){
50998 return this.height;
51001 getSignature : function(){
51002 return this.signatureTmp;
51005 reset : function(){
51006 this.signatureTmp = '';
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', '');
51009 this.isConfirmed = false;
51010 Roo.form.Signature.superclass.reset.call(this);
51012 setSignature : function(s){
51013 this.signatureTmp = s;
51014 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
51015 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
51017 this.isConfirmed = false;
51018 Roo.form.Signature.superclass.reset.call(this);
51021 // Roo.log(this.signPanel.dom.contentWindow.up())
51024 setConfirmed : function(){
51028 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
51031 confirmHandler : function(){
51032 if(!this.getSignature()){
51036 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
51037 this.setValue(this.getSignature());
51038 this.isConfirmed = true;
51040 this.fireEvent('confirm', this);
51043 // Subclasses should provide the validation implementation by overriding this
51044 validateValue : function(value){
51045 if(this.allowBlank){
51049 if(this.isConfirmed){
51056 * Ext JS Library 1.1.1
51057 * Copyright(c) 2006-2007, Ext JS, LLC.
51059 * Originally Released Under LGPL - original licence link has changed is not relivant.
51062 * <script type="text/javascript">
51067 * @class Roo.form.ComboBox
51068 * @extends Roo.form.TriggerField
51069 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
51071 * Create a new ComboBox.
51072 * @param {Object} config Configuration options
51074 Roo.form.Select = function(config){
51075 Roo.form.Select.superclass.constructor.call(this, config);
51079 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
51081 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
51084 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
51085 * rendering into an Roo.Editor, defaults to false)
51088 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
51089 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
51092 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
51095 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
51096 * the dropdown list (defaults to undefined, with no header element)
51100 * @cfg {String/Roo.Template} tpl The template to use to render the output
51104 defaultAutoCreate : {tag: "select" },
51106 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
51108 listWidth: undefined,
51110 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
51111 * mode = 'remote' or 'text' if mode = 'local')
51113 displayField: undefined,
51115 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
51116 * mode = 'remote' or 'value' if mode = 'local').
51117 * Note: use of a valueField requires the user make a selection
51118 * in order for a value to be mapped.
51120 valueField: undefined,
51124 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
51125 * field's data value (defaults to the underlying DOM element's name)
51127 hiddenName: undefined,
51129 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
51133 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
51135 selectedClass: 'x-combo-selected',
51137 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
51138 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
51139 * which displays a downward arrow icon).
51141 triggerClass : 'x-form-arrow-trigger',
51143 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
51147 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
51148 * anchor positions (defaults to 'tl-bl')
51150 listAlign: 'tl-bl?',
51152 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
51156 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
51157 * query specified by the allQuery config option (defaults to 'query')
51159 triggerAction: 'query',
51161 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
51162 * (defaults to 4, does not apply if editable = false)
51166 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
51167 * delay (typeAheadDelay) if it matches a known value (defaults to false)
51171 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
51172 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
51176 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
51177 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
51181 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
51182 * when editable = true (defaults to false)
51184 selectOnFocus:false,
51186 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
51188 queryParam: 'query',
51190 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
51191 * when mode = 'remote' (defaults to 'Loading...')
51193 loadingText: 'Loading...',
51195 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
51199 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
51203 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
51204 * traditional select (defaults to true)
51208 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
51212 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
51216 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
51217 * listWidth has a higher value)
51221 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
51222 * allow the user to set arbitrary text into the field (defaults to false)
51224 forceSelection:false,
51226 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
51227 * if typeAhead = true (defaults to 250)
51229 typeAheadDelay : 250,
51231 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
51232 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51234 valueNotFoundText : undefined,
51237 * @cfg {String} defaultValue The value displayed after loading the store.
51242 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51244 blockFocus : false,
51247 * @cfg {Boolean} disableClear Disable showing of clear button.
51249 disableClear : false,
51251 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51253 alwaysQuery : false,
51259 // element that contains real text value.. (when hidden is used..)
51262 onRender : function(ct, position){
51263 Roo.form.Field.prototype.onRender.call(this, ct, position);
51266 this.store.on('beforeload', this.onBeforeLoad, this);
51267 this.store.on('load', this.onLoad, this);
51268 this.store.on('loadexception', this.onLoadException, this);
51269 this.store.load({});
51277 initEvents : function(){
51278 //Roo.form.ComboBox.superclass.initEvents.call(this);
51282 onDestroy : function(){
51285 this.store.un('beforeload', this.onBeforeLoad, this);
51286 this.store.un('load', this.onLoad, this);
51287 this.store.un('loadexception', this.onLoadException, this);
51289 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51293 fireKey : function(e){
51294 if(e.isNavKeyPress() && !this.list.isVisible()){
51295 this.fireEvent("specialkey", this, e);
51300 onResize: function(w, h){
51308 * Allow or prevent the user from directly editing the field text. If false is passed,
51309 * the user will only be able to select from the items defined in the dropdown list. This method
51310 * is the runtime equivalent of setting the 'editable' config option at config time.
51311 * @param {Boolean} value True to allow the user to directly edit the field text
51313 setEditable : function(value){
51318 onBeforeLoad : function(){
51320 Roo.log("Select before load");
51323 this.innerList.update(this.loadingText ?
51324 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51325 //this.restrictHeight();
51326 this.selectedIndex = -1;
51330 onLoad : function(){
51333 var dom = this.el.dom;
51334 dom.innerHTML = '';
51335 var od = dom.ownerDocument;
51337 if (this.emptyText) {
51338 var op = od.createElement('option');
51339 op.setAttribute('value', '');
51340 op.innerHTML = String.format('{0}', this.emptyText);
51341 dom.appendChild(op);
51343 if(this.store.getCount() > 0){
51345 var vf = this.valueField;
51346 var df = this.displayField;
51347 this.store.data.each(function(r) {
51348 // which colmsn to use... testing - cdoe / title..
51349 var op = od.createElement('option');
51350 op.setAttribute('value', r.data[vf]);
51351 op.innerHTML = String.format('{0}', r.data[df]);
51352 dom.appendChild(op);
51354 if (typeof(this.defaultValue != 'undefined')) {
51355 this.setValue(this.defaultValue);
51360 //this.onEmptyResults();
51365 onLoadException : function()
51367 dom.innerHTML = '';
51369 Roo.log("Select on load exception");
51373 Roo.log(this.store.reader.jsonData);
51374 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51375 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51381 onTypeAhead : function(){
51386 onSelect : function(record, index){
51387 Roo.log('on select?');
51389 if(this.fireEvent('beforeselect', this, record, index) !== false){
51390 this.setFromData(index > -1 ? record.data : false);
51392 this.fireEvent('select', this, record, index);
51397 * Returns the currently selected field value or empty string if no value is set.
51398 * @return {String} value The selected value
51400 getValue : function(){
51401 var dom = this.el.dom;
51402 this.value = dom.options[dom.selectedIndex].value;
51408 * Clears any text/value currently set in the field
51410 clearValue : function(){
51412 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51417 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51418 * will be displayed in the field. If the value does not match the data value of an existing item,
51419 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51420 * Otherwise the field will be blank (although the value will still be set).
51421 * @param {String} value The value to match
51423 setValue : function(v){
51424 var d = this.el.dom;
51425 for (var i =0; i < d.options.length;i++) {
51426 if (v == d.options[i].value) {
51427 d.selectedIndex = i;
51435 * @property {Object} the last set data for the element
51440 * Sets the value of the field based on a object which is related to the record format for the store.
51441 * @param {Object} value the value to set as. or false on reset?
51443 setFromData : function(o){
51444 Roo.log('setfrom data?');
51450 reset : function(){
51454 findRecord : function(prop, value){
51459 if(this.store.getCount() > 0){
51460 this.store.each(function(r){
51461 if(r.data[prop] == value){
51471 getName: function()
51473 // returns hidden if it's set..
51474 if (!this.rendered) {return ''};
51475 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51483 onEmptyResults : function(){
51484 Roo.log('empty results');
51489 * Returns true if the dropdown list is expanded, else false.
51491 isExpanded : function(){
51496 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51497 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51498 * @param {String} value The data value of the item to select
51499 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51500 * selected item if it is not currently in view (defaults to true)
51501 * @return {Boolean} True if the value matched an item in the list, else false
51503 selectByValue : function(v, scrollIntoView){
51504 Roo.log('select By Value');
51507 if(v !== undefined && v !== null){
51508 var r = this.findRecord(this.valueField || this.displayField, v);
51510 this.select(this.store.indexOf(r), scrollIntoView);
51518 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51519 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51520 * @param {Number} index The zero-based index of the list item to select
51521 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51522 * selected item if it is not currently in view (defaults to true)
51524 select : function(index, scrollIntoView){
51525 Roo.log('select ');
51528 this.selectedIndex = index;
51529 this.view.select(index);
51530 if(scrollIntoView !== false){
51531 var el = this.view.getNode(index);
51533 this.innerList.scrollChildIntoView(el, false);
51541 validateBlur : function(){
51548 initQuery : function(){
51549 this.doQuery(this.getRawValue());
51553 doForce : function(){
51554 if(this.el.dom.value.length > 0){
51555 this.el.dom.value =
51556 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51562 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51563 * query allowing the query action to be canceled if needed.
51564 * @param {String} query The SQL query to execute
51565 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51566 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51567 * saved in the current store (defaults to false)
51569 doQuery : function(q, forceAll){
51571 Roo.log('doQuery?');
51572 if(q === undefined || q === null){
51577 forceAll: forceAll,
51581 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51585 forceAll = qe.forceAll;
51586 if(forceAll === true || (q.length >= this.minChars)){
51587 if(this.lastQuery != q || this.alwaysQuery){
51588 this.lastQuery = q;
51589 if(this.mode == 'local'){
51590 this.selectedIndex = -1;
51592 this.store.clearFilter();
51594 this.store.filter(this.displayField, q);
51598 this.store.baseParams[this.queryParam] = q;
51600 params: this.getParams(q)
51605 this.selectedIndex = -1;
51612 getParams : function(q){
51614 //p[this.queryParam] = q;
51617 p.limit = this.pageSize;
51623 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51625 collapse : function(){
51630 collapseIf : function(e){
51635 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51637 expand : function(){
51645 * @cfg {Boolean} grow
51649 * @cfg {Number} growMin
51653 * @cfg {Number} growMax
51661 setWidth : function()
51665 getResizeEl : function(){
51668 });//<script type="text/javasscript">
51672 * @class Roo.DDView
51673 * A DnD enabled version of Roo.View.
51674 * @param {Element/String} container The Element in which to create the View.
51675 * @param {String} tpl The template string used to create the markup for each element of the View
51676 * @param {Object} config The configuration properties. These include all the config options of
51677 * {@link Roo.View} plus some specific to this class.<br>
51679 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51680 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51682 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51683 .x-view-drag-insert-above {
51684 border-top:1px dotted #3366cc;
51686 .x-view-drag-insert-below {
51687 border-bottom:1px dotted #3366cc;
51693 Roo.DDView = function(container, tpl, config) {
51694 Roo.DDView.superclass.constructor.apply(this, arguments);
51695 this.getEl().setStyle("outline", "0px none");
51696 this.getEl().unselectable();
51697 if (this.dragGroup) {
51698 this.setDraggable(this.dragGroup.split(","));
51700 if (this.dropGroup) {
51701 this.setDroppable(this.dropGroup.split(","));
51703 if (this.deletable) {
51704 this.setDeletable();
51706 this.isDirtyFlag = false;
51712 Roo.extend(Roo.DDView, Roo.View, {
51713 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51714 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51715 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51716 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51720 reset: Roo.emptyFn,
51722 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51724 validate: function() {
51728 destroy: function() {
51729 this.purgeListeners();
51730 this.getEl.removeAllListeners();
51731 this.getEl().remove();
51732 if (this.dragZone) {
51733 if (this.dragZone.destroy) {
51734 this.dragZone.destroy();
51737 if (this.dropZone) {
51738 if (this.dropZone.destroy) {
51739 this.dropZone.destroy();
51744 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51745 getName: function() {
51749 /** Loads the View from a JSON string representing the Records to put into the Store. */
51750 setValue: function(v) {
51752 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51755 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51756 this.store.proxy = new Roo.data.MemoryProxy(data);
51760 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51761 getValue: function() {
51763 this.store.each(function(rec) {
51764 result += rec.id + ',';
51766 return result.substr(0, result.length - 1) + ')';
51769 getIds: function() {
51770 var i = 0, result = new Array(this.store.getCount());
51771 this.store.each(function(rec) {
51772 result[i++] = rec.id;
51777 isDirty: function() {
51778 return this.isDirtyFlag;
51782 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51783 * whole Element becomes the target, and this causes the drop gesture to append.
51785 getTargetFromEvent : function(e) {
51786 var target = e.getTarget();
51787 while ((target !== null) && (target.parentNode != this.el.dom)) {
51788 target = target.parentNode;
51791 target = this.el.dom.lastChild || this.el.dom;
51797 * Create the drag data which consists of an object which has the property "ddel" as
51798 * the drag proxy element.
51800 getDragData : function(e) {
51801 var target = this.findItemFromChild(e.getTarget());
51803 this.handleSelection(e);
51804 var selNodes = this.getSelectedNodes();
51807 copy: this.copy || (this.allowCopy && e.ctrlKey),
51811 var selectedIndices = this.getSelectedIndexes();
51812 for (var i = 0; i < selectedIndices.length; i++) {
51813 dragData.records.push(this.store.getAt(selectedIndices[i]));
51815 if (selNodes.length == 1) {
51816 dragData.ddel = target.cloneNode(true); // the div element
51818 var div = document.createElement('div'); // create the multi element drag "ghost"
51819 div.className = 'multi-proxy';
51820 for (var i = 0, len = selNodes.length; i < len; i++) {
51821 div.appendChild(selNodes[i].cloneNode(true));
51823 dragData.ddel = div;
51825 //console.log(dragData)
51826 //console.log(dragData.ddel.innerHTML)
51829 //console.log('nodragData')
51833 /** Specify to which ddGroup items in this DDView may be dragged. */
51834 setDraggable: function(ddGroup) {
51835 if (ddGroup instanceof Array) {
51836 Roo.each(ddGroup, this.setDraggable, this);
51839 if (this.dragZone) {
51840 this.dragZone.addToGroup(ddGroup);
51842 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51843 containerScroll: true,
51847 // Draggability implies selection. DragZone's mousedown selects the element.
51848 if (!this.multiSelect) { this.singleSelect = true; }
51850 // Wire the DragZone's handlers up to methods in *this*
51851 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51855 /** Specify from which ddGroup this DDView accepts drops. */
51856 setDroppable: function(ddGroup) {
51857 if (ddGroup instanceof Array) {
51858 Roo.each(ddGroup, this.setDroppable, this);
51861 if (this.dropZone) {
51862 this.dropZone.addToGroup(ddGroup);
51864 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51865 containerScroll: true,
51869 // Wire the DropZone's handlers up to methods in *this*
51870 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51871 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51872 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51873 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51874 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51878 /** Decide whether to drop above or below a View node. */
51879 getDropPoint : function(e, n, dd){
51880 if (n == this.el.dom) { return "above"; }
51881 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51882 var c = t + (b - t) / 2;
51883 var y = Roo.lib.Event.getPageY(e);
51891 onNodeEnter : function(n, dd, e, data){
51895 onNodeOver : function(n, dd, e, data){
51896 var pt = this.getDropPoint(e, n, dd);
51897 // set the insert point style on the target node
51898 var dragElClass = this.dropNotAllowed;
51901 if (pt == "above"){
51902 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51903 targetElClass = "x-view-drag-insert-above";
51905 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51906 targetElClass = "x-view-drag-insert-below";
51908 if (this.lastInsertClass != targetElClass){
51909 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51910 this.lastInsertClass = targetElClass;
51913 return dragElClass;
51916 onNodeOut : function(n, dd, e, data){
51917 this.removeDropIndicators(n);
51920 onNodeDrop : function(n, dd, e, data){
51921 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51924 var pt = this.getDropPoint(e, n, dd);
51925 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51926 if (pt == "below") { insertAt++; }
51927 for (var i = 0; i < data.records.length; i++) {
51928 var r = data.records[i];
51929 var dup = this.store.getById(r.id);
51930 if (dup && (dd != this.dragZone)) {
51931 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51934 this.store.insert(insertAt++, r.copy());
51936 data.source.isDirtyFlag = true;
51938 this.store.insert(insertAt++, r);
51940 this.isDirtyFlag = true;
51943 this.dragZone.cachedTarget = null;
51947 removeDropIndicators : function(n){
51949 Roo.fly(n).removeClass([
51950 "x-view-drag-insert-above",
51951 "x-view-drag-insert-below"]);
51952 this.lastInsertClass = "_noclass";
51957 * Utility method. Add a delete option to the DDView's context menu.
51958 * @param {String} imageUrl The URL of the "delete" icon image.
51960 setDeletable: function(imageUrl) {
51961 if (!this.singleSelect && !this.multiSelect) {
51962 this.singleSelect = true;
51964 var c = this.getContextMenu();
51965 this.contextMenu.on("itemclick", function(item) {
51968 this.remove(this.getSelectedIndexes());
51972 this.contextMenu.add({
51979 /** Return the context menu for this DDView. */
51980 getContextMenu: function() {
51981 if (!this.contextMenu) {
51982 // Create the View's context menu
51983 this.contextMenu = new Roo.menu.Menu({
51984 id: this.id + "-contextmenu"
51986 this.el.on("contextmenu", this.showContextMenu, this);
51988 return this.contextMenu;
51991 disableContextMenu: function() {
51992 if (this.contextMenu) {
51993 this.el.un("contextmenu", this.showContextMenu, this);
51997 showContextMenu: function(e, item) {
51998 item = this.findItemFromChild(e.getTarget());
52001 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
52002 this.contextMenu.showAt(e.getXY());
52007 * Remove {@link Roo.data.Record}s at the specified indices.
52008 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
52010 remove: function(selectedIndices) {
52011 selectedIndices = [].concat(selectedIndices);
52012 for (var i = 0; i < selectedIndices.length; i++) {
52013 var rec = this.store.getAt(selectedIndices[i]);
52014 this.store.remove(rec);
52019 * Double click fires the event, but also, if this is draggable, and there is only one other
52020 * related DropZone, it transfers the selected node.
52022 onDblClick : function(e){
52023 var item = this.findItemFromChild(e.getTarget());
52025 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
52028 if (this.dragGroup) {
52029 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
52030 while (targets.indexOf(this.dropZone) > -1) {
52031 targets.remove(this.dropZone);
52033 if (targets.length == 1) {
52034 this.dragZone.cachedTarget = null;
52035 var el = Roo.get(targets[0].getEl());
52036 var box = el.getBox(true);
52037 targets[0].onNodeDrop(el.dom, {
52039 xy: [box.x, box.y + box.height - 1]
52040 }, null, this.getDragData(e));
52046 handleSelection: function(e) {
52047 this.dragZone.cachedTarget = null;
52048 var item = this.findItemFromChild(e.getTarget());
52050 this.clearSelections(true);
52053 if (item && (this.multiSelect || this.singleSelect)){
52054 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
52055 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
52056 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
52057 this.unselect(item);
52059 this.select(item, this.multiSelect && e.ctrlKey);
52060 this.lastSelection = item;
52065 onItemClick : function(item, index, e){
52066 if(this.fireEvent("beforeclick", this, index, item, e) === false){
52072 unselect : function(nodeInfo, suppressEvent){
52073 var node = this.getNode(nodeInfo);
52074 if(node && this.isSelected(node)){
52075 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
52076 Roo.fly(node).removeClass(this.selectedClass);
52077 this.selections.remove(node);
52078 if(!suppressEvent){
52079 this.fireEvent("selectionchange", this, this.selections);
52087 * Ext JS Library 1.1.1
52088 * Copyright(c) 2006-2007, Ext JS, LLC.
52090 * Originally Released Under LGPL - original licence link has changed is not relivant.
52093 * <script type="text/javascript">
52097 * @class Roo.LayoutManager
52098 * @extends Roo.util.Observable
52099 * Base class for layout managers.
52101 Roo.LayoutManager = function(container, config){
52102 Roo.LayoutManager.superclass.constructor.call(this);
52103 this.el = Roo.get(container);
52104 // ie scrollbar fix
52105 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
52106 document.body.scroll = "no";
52107 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
52108 this.el.position('relative');
52110 this.id = this.el.id;
52111 this.el.addClass("x-layout-container");
52112 /** false to disable window resize monitoring @type Boolean */
52113 this.monitorWindowResize = true;
52118 * Fires when a layout is performed.
52119 * @param {Roo.LayoutManager} this
52123 * @event regionresized
52124 * Fires when the user resizes a region.
52125 * @param {Roo.LayoutRegion} region The resized region
52126 * @param {Number} newSize The new size (width for east/west, height for north/south)
52128 "regionresized" : true,
52130 * @event regioncollapsed
52131 * Fires when a region is collapsed.
52132 * @param {Roo.LayoutRegion} region The collapsed region
52134 "regioncollapsed" : true,
52136 * @event regionexpanded
52137 * Fires when a region is expanded.
52138 * @param {Roo.LayoutRegion} region The expanded region
52140 "regionexpanded" : true
52142 this.updating = false;
52143 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52146 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
52148 * Returns true if this layout is currently being updated
52149 * @return {Boolean}
52151 isUpdating : function(){
52152 return this.updating;
52156 * Suspend the LayoutManager from doing auto-layouts while
52157 * making multiple add or remove calls
52159 beginUpdate : function(){
52160 this.updating = true;
52164 * Restore auto-layouts and optionally disable the manager from performing a layout
52165 * @param {Boolean} noLayout true to disable a layout update
52167 endUpdate : function(noLayout){
52168 this.updating = false;
52174 layout: function(){
52178 onRegionResized : function(region, newSize){
52179 this.fireEvent("regionresized", region, newSize);
52183 onRegionCollapsed : function(region){
52184 this.fireEvent("regioncollapsed", region);
52187 onRegionExpanded : function(region){
52188 this.fireEvent("regionexpanded", region);
52192 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
52193 * performs box-model adjustments.
52194 * @return {Object} The size as an object {width: (the width), height: (the height)}
52196 getViewSize : function(){
52198 if(this.el.dom != document.body){
52199 size = this.el.getSize();
52201 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
52203 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
52204 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
52209 * Returns the Element this layout is bound to.
52210 * @return {Roo.Element}
52212 getEl : function(){
52217 * Returns the specified region.
52218 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
52219 * @return {Roo.LayoutRegion}
52221 getRegion : function(target){
52222 return this.regions[target.toLowerCase()];
52225 onWindowResize : function(){
52226 if(this.monitorWindowResize){
52232 * Ext JS Library 1.1.1
52233 * Copyright(c) 2006-2007, Ext JS, LLC.
52235 * Originally Released Under LGPL - original licence link has changed is not relivant.
52238 * <script type="text/javascript">
52241 * @class Roo.BorderLayout
52242 * @extends Roo.LayoutManager
52243 * @children Roo.ContentPanel
52244 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52245 * please see: <br><br>
52246 * <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>
52247 * <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>
52250 var layout = new Roo.BorderLayout(document.body, {
52284 preferredTabWidth: 150
52289 var CP = Roo.ContentPanel;
52291 layout.beginUpdate();
52292 layout.add("north", new CP("north", "North"));
52293 layout.add("south", new CP("south", {title: "South", closable: true}));
52294 layout.add("west", new CP("west", {title: "West"}));
52295 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52296 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52297 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52298 layout.getRegion("center").showPanel("center1");
52299 layout.endUpdate();
52302 <b>The container the layout is rendered into can be either the body element or any other element.
52303 If it is not the body element, the container needs to either be an absolute positioned element,
52304 or you will need to add "position:relative" to the css of the container. You will also need to specify
52305 the container size if it is not the body element.</b>
52308 * Create a new BorderLayout
52309 * @param {String/HTMLElement/Element} container The container this layout is bound to
52310 * @param {Object} config Configuration options
52312 Roo.BorderLayout = function(container, config){
52313 config = config || {};
52314 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52315 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52316 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52317 var target = this.factory.validRegions[i];
52318 if(config[target]){
52319 this.addRegion(target, config[target]);
52324 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52327 * @cfg {Roo.LayoutRegion} east
52330 * @cfg {Roo.LayoutRegion} west
52333 * @cfg {Roo.LayoutRegion} north
52336 * @cfg {Roo.LayoutRegion} south
52339 * @cfg {Roo.LayoutRegion} center
52342 * Creates and adds a new region if it doesn't already exist.
52343 * @param {String} target The target region key (north, south, east, west or center).
52344 * @param {Object} config The regions config object
52345 * @return {BorderLayoutRegion} The new region
52347 addRegion : function(target, config){
52348 if(!this.regions[target]){
52349 var r = this.factory.create(target, this, config);
52350 this.bindRegion(target, r);
52352 return this.regions[target];
52356 bindRegion : function(name, r){
52357 this.regions[name] = r;
52358 r.on("visibilitychange", this.layout, this);
52359 r.on("paneladded", this.layout, this);
52360 r.on("panelremoved", this.layout, this);
52361 r.on("invalidated", this.layout, this);
52362 r.on("resized", this.onRegionResized, this);
52363 r.on("collapsed", this.onRegionCollapsed, this);
52364 r.on("expanded", this.onRegionExpanded, this);
52368 * Performs a layout update.
52370 layout : function(){
52371 if(this.updating) {
52374 var size = this.getViewSize();
52375 var w = size.width;
52376 var h = size.height;
52381 //var x = 0, y = 0;
52383 var rs = this.regions;
52384 var north = rs["north"];
52385 var south = rs["south"];
52386 var west = rs["west"];
52387 var east = rs["east"];
52388 var center = rs["center"];
52389 //if(this.hideOnLayout){ // not supported anymore
52390 //c.el.setStyle("display", "none");
52392 if(north && north.isVisible()){
52393 var b = north.getBox();
52394 var m = north.getMargins();
52395 b.width = w - (m.left+m.right);
52398 centerY = b.height + b.y + m.bottom;
52399 centerH -= centerY;
52400 north.updateBox(this.safeBox(b));
52402 if(south && south.isVisible()){
52403 var b = south.getBox();
52404 var m = south.getMargins();
52405 b.width = w - (m.left+m.right);
52407 var totalHeight = (b.height + m.top + m.bottom);
52408 b.y = h - totalHeight + m.top;
52409 centerH -= totalHeight;
52410 south.updateBox(this.safeBox(b));
52412 if(west && west.isVisible()){
52413 var b = west.getBox();
52414 var m = west.getMargins();
52415 b.height = centerH - (m.top+m.bottom);
52417 b.y = centerY + m.top;
52418 var totalWidth = (b.width + m.left + m.right);
52419 centerX += totalWidth;
52420 centerW -= totalWidth;
52421 west.updateBox(this.safeBox(b));
52423 if(east && east.isVisible()){
52424 var b = east.getBox();
52425 var m = east.getMargins();
52426 b.height = centerH - (m.top+m.bottom);
52427 var totalWidth = (b.width + m.left + m.right);
52428 b.x = w - totalWidth + m.left;
52429 b.y = centerY + m.top;
52430 centerW -= totalWidth;
52431 east.updateBox(this.safeBox(b));
52434 var m = center.getMargins();
52436 x: centerX + m.left,
52437 y: centerY + m.top,
52438 width: centerW - (m.left+m.right),
52439 height: centerH - (m.top+m.bottom)
52441 //if(this.hideOnLayout){
52442 //center.el.setStyle("display", "block");
52444 center.updateBox(this.safeBox(centerBox));
52447 this.fireEvent("layout", this);
52451 safeBox : function(box){
52452 box.width = Math.max(0, box.width);
52453 box.height = Math.max(0, box.height);
52458 * Adds a ContentPanel (or subclass) to this layout.
52459 * @param {String} target The target region key (north, south, east, west or center).
52460 * @param {Roo.ContentPanel} panel The panel to add
52461 * @return {Roo.ContentPanel} The added panel
52463 add : function(target, panel){
52465 target = target.toLowerCase();
52466 return this.regions[target].add(panel);
52470 * Remove a ContentPanel (or subclass) to this layout.
52471 * @param {String} target The target region key (north, south, east, west or center).
52472 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52473 * @return {Roo.ContentPanel} The removed panel
52475 remove : function(target, panel){
52476 target = target.toLowerCase();
52477 return this.regions[target].remove(panel);
52481 * Searches all regions for a panel with the specified id
52482 * @param {String} panelId
52483 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52485 findPanel : function(panelId){
52486 var rs = this.regions;
52487 for(var target in rs){
52488 if(typeof rs[target] != "function"){
52489 var p = rs[target].getPanel(panelId);
52499 * Searches all regions for a panel with the specified id and activates (shows) it.
52500 * @param {String/ContentPanel} panelId The panels id or the panel itself
52501 * @return {Roo.ContentPanel} The shown panel or null
52503 showPanel : function(panelId) {
52504 var rs = this.regions;
52505 for(var target in rs){
52506 var r = rs[target];
52507 if(typeof r != "function"){
52508 if(r.hasPanel(panelId)){
52509 return r.showPanel(panelId);
52517 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52518 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52520 restoreState : function(provider){
52522 provider = Roo.state.Manager;
52524 var sm = new Roo.LayoutStateManager();
52525 sm.init(this, provider);
52529 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52530 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52531 * a valid ContentPanel config object. Example:
52533 // Create the main layout
52534 var layout = new Roo.BorderLayout('main-ct', {
52545 // Create and add multiple ContentPanels at once via configs
52548 id: 'source-files',
52550 title:'Ext Source Files',
52563 * @param {Object} regions An object containing ContentPanel configs by region name
52565 batchAdd : function(regions){
52566 this.beginUpdate();
52567 for(var rname in regions){
52568 var lr = this.regions[rname];
52570 this.addTypedPanels(lr, regions[rname]);
52577 addTypedPanels : function(lr, ps){
52578 if(typeof ps == 'string'){
52579 lr.add(new Roo.ContentPanel(ps));
52581 else if(ps instanceof Array){
52582 for(var i =0, len = ps.length; i < len; i++){
52583 this.addTypedPanels(lr, ps[i]);
52586 else if(!ps.events){ // raw config?
52588 delete ps.el; // prevent conflict
52589 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52591 else { // panel object assumed!
52596 * Adds a xtype elements to the layout.
52600 xtype : 'ContentPanel',
52607 xtype : 'NestedLayoutPanel',
52613 items : [ ... list of content panels or nested layout panels.. ]
52617 * @param {Object} cfg Xtype definition of item to add.
52619 addxtype : function(cfg)
52621 // basically accepts a pannel...
52622 // can accept a layout region..!?!?
52623 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52625 if (!cfg.xtype.match(/Panel$/)) {
52630 if (typeof(cfg.region) == 'undefined') {
52631 Roo.log("Failed to add Panel, region was not set");
52635 var region = cfg.region;
52641 xitems = cfg.items;
52648 case 'ContentPanel': // ContentPanel (el, cfg)
52649 case 'ScrollPanel': // ContentPanel (el, cfg)
52651 if(cfg.autoCreate) {
52652 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52654 var el = this.el.createChild();
52655 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52658 this.add(region, ret);
52662 case 'TreePanel': // our new panel!
52663 cfg.el = this.el.createChild();
52664 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52665 this.add(region, ret);
52668 case 'NestedLayoutPanel':
52669 // create a new Layout (which is a Border Layout...
52670 var el = this.el.createChild();
52671 var clayout = cfg.layout;
52673 clayout.items = clayout.items || [];
52674 // replace this exitems with the clayout ones..
52675 xitems = clayout.items;
52678 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52679 cfg.background = false;
52681 var layout = new Roo.BorderLayout(el, clayout);
52683 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52684 //console.log('adding nested layout panel ' + cfg.toSource());
52685 this.add(region, ret);
52686 nb = {}; /// find first...
52691 // needs grid and region
52693 //var el = this.getRegion(region).el.createChild();
52694 var el = this.el.createChild();
52695 // create the grid first...
52697 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52699 if (region == 'center' && this.active ) {
52700 cfg.background = false;
52702 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52704 this.add(region, ret);
52705 if (cfg.background) {
52706 ret.on('activate', function(gp) {
52707 if (!gp.grid.rendered) {
52722 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52724 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52725 this.add(region, ret);
52728 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52732 // GridPanel (grid, cfg)
52735 this.beginUpdate();
52739 Roo.each(xitems, function(i) {
52740 region = nb && i.region ? i.region : false;
52742 var add = ret.addxtype(i);
52745 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52746 if (!i.background) {
52747 abn[region] = nb[region] ;
52754 // make the last non-background panel active..
52755 //if (nb) { Roo.log(abn); }
52758 for(var r in abn) {
52759 region = this.getRegion(r);
52761 // tried using nb[r], but it does not work..
52763 region.showPanel(abn[r]);
52774 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52775 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52776 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52777 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52780 var CP = Roo.ContentPanel;
52782 var layout = Roo.BorderLayout.create({
52786 panels: [new CP("north", "North")]
52795 panels: [new CP("west", {title: "West"})]
52804 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52813 panels: [new CP("south", {title: "South", closable: true})]
52820 preferredTabWidth: 150,
52822 new CP("center1", {title: "Close Me", closable: true}),
52823 new CP("center2", {title: "Center Panel", closable: false})
52828 layout.getRegion("center").showPanel("center1");
52833 Roo.BorderLayout.create = function(config, targetEl){
52834 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52835 layout.beginUpdate();
52836 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52837 for(var j = 0, jlen = regions.length; j < jlen; j++){
52838 var lr = regions[j];
52839 if(layout.regions[lr] && config[lr].panels){
52840 var r = layout.regions[lr];
52841 var ps = config[lr].panels;
52842 layout.addTypedPanels(r, ps);
52845 layout.endUpdate();
52850 Roo.BorderLayout.RegionFactory = {
52852 validRegions : ["north","south","east","west","center"],
52855 create : function(target, mgr, config){
52856 target = target.toLowerCase();
52857 if(config.lightweight || config.basic){
52858 return new Roo.BasicLayoutRegion(mgr, config, target);
52862 return new Roo.NorthLayoutRegion(mgr, config);
52864 return new Roo.SouthLayoutRegion(mgr, config);
52866 return new Roo.EastLayoutRegion(mgr, config);
52868 return new Roo.WestLayoutRegion(mgr, config);
52870 return new Roo.CenterLayoutRegion(mgr, config);
52872 throw 'Layout region "'+target+'" not supported.';
52876 * Ext JS Library 1.1.1
52877 * Copyright(c) 2006-2007, Ext JS, LLC.
52879 * Originally Released Under LGPL - original licence link has changed is not relivant.
52882 * <script type="text/javascript">
52886 * @class Roo.BasicLayoutRegion
52887 * @extends Roo.util.Observable
52888 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52889 * and does not have a titlebar, tabs or any other features. All it does is size and position
52890 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52892 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52894 this.position = pos;
52897 * @scope Roo.BasicLayoutRegion
52901 * @event beforeremove
52902 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52903 * @param {Roo.LayoutRegion} this
52904 * @param {Roo.ContentPanel} panel The panel
52905 * @param {Object} e The cancel event object
52907 "beforeremove" : true,
52909 * @event invalidated
52910 * Fires when the layout for this region is changed.
52911 * @param {Roo.LayoutRegion} this
52913 "invalidated" : true,
52915 * @event visibilitychange
52916 * Fires when this region is shown or hidden
52917 * @param {Roo.LayoutRegion} this
52918 * @param {Boolean} visibility true or false
52920 "visibilitychange" : true,
52922 * @event paneladded
52923 * Fires when a panel is added.
52924 * @param {Roo.LayoutRegion} this
52925 * @param {Roo.ContentPanel} panel The panel
52927 "paneladded" : true,
52929 * @event panelremoved
52930 * Fires when a panel is removed.
52931 * @param {Roo.LayoutRegion} this
52932 * @param {Roo.ContentPanel} panel The panel
52934 "panelremoved" : true,
52936 * @event beforecollapse
52937 * Fires when this region before collapse.
52938 * @param {Roo.LayoutRegion} this
52940 "beforecollapse" : true,
52943 * Fires when this region is collapsed.
52944 * @param {Roo.LayoutRegion} this
52946 "collapsed" : true,
52949 * Fires when this region is expanded.
52950 * @param {Roo.LayoutRegion} this
52955 * Fires when this region is slid into view.
52956 * @param {Roo.LayoutRegion} this
52958 "slideshow" : true,
52961 * Fires when this region slides out of view.
52962 * @param {Roo.LayoutRegion} this
52964 "slidehide" : true,
52966 * @event panelactivated
52967 * Fires when a panel is activated.
52968 * @param {Roo.LayoutRegion} this
52969 * @param {Roo.ContentPanel} panel The activated panel
52971 "panelactivated" : true,
52974 * Fires when the user resizes this region.
52975 * @param {Roo.LayoutRegion} this
52976 * @param {Number} newSize The new size (width for east/west, height for north/south)
52980 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52981 this.panels = new Roo.util.MixedCollection();
52982 this.panels.getKey = this.getPanelId.createDelegate(this);
52984 this.activePanel = null;
52985 // ensure listeners are added...
52987 if (config.listeners || config.events) {
52988 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52989 listeners : config.listeners || {},
52990 events : config.events || {}
52994 if(skipConfig !== true){
52995 this.applyConfig(config);
52999 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
53000 getPanelId : function(p){
53004 applyConfig : function(config){
53005 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53006 this.config = config;
53011 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
53012 * the width, for horizontal (north, south) the height.
53013 * @param {Number} newSize The new width or height
53015 resizeTo : function(newSize){
53016 var el = this.el ? this.el :
53017 (this.activePanel ? this.activePanel.getEl() : null);
53019 switch(this.position){
53022 el.setWidth(newSize);
53023 this.fireEvent("resized", this, newSize);
53027 el.setHeight(newSize);
53028 this.fireEvent("resized", this, newSize);
53034 getBox : function(){
53035 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
53038 getMargins : function(){
53039 return this.margins;
53042 updateBox : function(box){
53044 var el = this.activePanel.getEl();
53045 el.dom.style.left = box.x + "px";
53046 el.dom.style.top = box.y + "px";
53047 this.activePanel.setSize(box.width, box.height);
53051 * Returns the container element for this region.
53052 * @return {Roo.Element}
53054 getEl : function(){
53055 return this.activePanel;
53059 * Returns true if this region is currently visible.
53060 * @return {Boolean}
53062 isVisible : function(){
53063 return this.activePanel ? true : false;
53066 setActivePanel : function(panel){
53067 panel = this.getPanel(panel);
53068 if(this.activePanel && this.activePanel != panel){
53069 this.activePanel.setActiveState(false);
53070 this.activePanel.getEl().setLeftTop(-10000,-10000);
53072 this.activePanel = panel;
53073 panel.setActiveState(true);
53075 panel.setSize(this.box.width, this.box.height);
53077 this.fireEvent("panelactivated", this, panel);
53078 this.fireEvent("invalidated");
53082 * Show the specified panel.
53083 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
53084 * @return {Roo.ContentPanel} The shown panel or null
53086 showPanel : function(panel){
53087 if(panel = this.getPanel(panel)){
53088 this.setActivePanel(panel);
53094 * Get the active panel for this region.
53095 * @return {Roo.ContentPanel} The active panel or null
53097 getActivePanel : function(){
53098 return this.activePanel;
53102 * Add the passed ContentPanel(s)
53103 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53104 * @return {Roo.ContentPanel} The panel added (if only one was added)
53106 add : function(panel){
53107 if(arguments.length > 1){
53108 for(var i = 0, len = arguments.length; i < len; i++) {
53109 this.add(arguments[i]);
53113 if(this.hasPanel(panel)){
53114 this.showPanel(panel);
53117 var el = panel.getEl();
53118 if(el.dom.parentNode != this.mgr.el.dom){
53119 this.mgr.el.dom.appendChild(el.dom);
53121 if(panel.setRegion){
53122 panel.setRegion(this);
53124 this.panels.add(panel);
53125 el.setStyle("position", "absolute");
53126 if(!panel.background){
53127 this.setActivePanel(panel);
53128 if(this.config.initialSize && this.panels.getCount()==1){
53129 this.resizeTo(this.config.initialSize);
53132 this.fireEvent("paneladded", this, panel);
53137 * Returns true if the panel is in this region.
53138 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53139 * @return {Boolean}
53141 hasPanel : function(panel){
53142 if(typeof panel == "object"){ // must be panel obj
53143 panel = panel.getId();
53145 return this.getPanel(panel) ? true : false;
53149 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53150 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53151 * @param {Boolean} preservePanel Overrides the config preservePanel option
53152 * @return {Roo.ContentPanel} The panel that was removed
53154 remove : function(panel, preservePanel){
53155 panel = this.getPanel(panel);
53160 this.fireEvent("beforeremove", this, panel, e);
53161 if(e.cancel === true){
53164 var panelId = panel.getId();
53165 this.panels.removeKey(panelId);
53170 * Returns the panel specified or null if it's not in this region.
53171 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53172 * @return {Roo.ContentPanel}
53174 getPanel : function(id){
53175 if(typeof id == "object"){ // must be panel obj
53178 return this.panels.get(id);
53182 * Returns this regions position (north/south/east/west/center).
53185 getPosition: function(){
53186 return this.position;
53190 * Ext JS Library 1.1.1
53191 * Copyright(c) 2006-2007, Ext JS, LLC.
53193 * Originally Released Under LGPL - original licence link has changed is not relivant.
53196 * <script type="text/javascript">
53200 * @class Roo.LayoutRegion
53201 * @extends Roo.BasicLayoutRegion
53202 * This class represents a region in a layout manager.
53203 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
53204 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
53205 * @cfg {Boolean} floatable False to disable floating (defaults to true)
53206 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
53207 * @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})
53208 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
53209 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
53210 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
53211 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
53212 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
53213 * @cfg {String} title The title for the region (overrides panel titles)
53214 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
53215 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
53216 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
53217 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
53218 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
53219 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
53220 * the space available, similar to FireFox 1.5 tabs (defaults to false)
53221 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
53222 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
53223 * @cfg {Boolean} showPin True to show a pin button
53224 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
53225 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
53226 * @cfg {Boolean} disableTabTips True to disable tab tooltips
53227 * @cfg {Number} width For East/West panels
53228 * @cfg {Number} height For North/South panels
53229 * @cfg {Boolean} split To show the splitter
53230 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
53232 Roo.LayoutRegion = function(mgr, config, pos){
53233 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
53234 var dh = Roo.DomHelper;
53235 /** This region's container element
53236 * @type Roo.Element */
53237 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
53238 /** This region's title element
53239 * @type Roo.Element */
53241 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
53242 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
53243 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
53245 this.titleEl.enableDisplayMode();
53246 /** This region's title text element
53247 * @type HTMLElement */
53248 this.titleTextEl = this.titleEl.dom.firstChild;
53249 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53250 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53251 this.closeBtn.enableDisplayMode();
53252 this.closeBtn.on("click", this.closeClicked, this);
53253 this.closeBtn.hide();
53255 this.createBody(config);
53256 this.visible = true;
53257 this.collapsed = false;
53259 if(config.hideWhenEmpty){
53261 this.on("paneladded", this.validateVisibility, this);
53262 this.on("panelremoved", this.validateVisibility, this);
53264 this.applyConfig(config);
53267 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53269 createBody : function(){
53270 /** This region's body element
53271 * @type Roo.Element */
53272 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53275 applyConfig : function(c){
53276 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53277 var dh = Roo.DomHelper;
53278 if(c.titlebar !== false){
53279 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53280 this.collapseBtn.on("click", this.collapse, this);
53281 this.collapseBtn.enableDisplayMode();
53283 if(c.showPin === true || this.showPin){
53284 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53285 this.stickBtn.enableDisplayMode();
53286 this.stickBtn.on("click", this.expand, this);
53287 this.stickBtn.hide();
53290 /** This region's collapsed element
53291 * @type Roo.Element */
53292 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53293 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53295 if(c.floatable !== false){
53296 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53297 this.collapsedEl.on("click", this.collapseClick, this);
53300 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53301 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53302 id: "message", unselectable: "on", style:{"float":"left"}});
53303 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53305 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53306 this.expandBtn.on("click", this.expand, this);
53308 if(this.collapseBtn){
53309 this.collapseBtn.setVisible(c.collapsible == true);
53311 this.cmargins = c.cmargins || this.cmargins ||
53312 (this.position == "west" || this.position == "east" ?
53313 {top: 0, left: 2, right:2, bottom: 0} :
53314 {top: 2, left: 0, right:0, bottom: 2});
53315 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53316 this.bottomTabs = c.tabPosition != "top";
53317 this.autoScroll = c.autoScroll || false;
53318 if(this.autoScroll){
53319 this.bodyEl.setStyle("overflow", "auto");
53321 this.bodyEl.setStyle("overflow", "hidden");
53323 //if(c.titlebar !== false){
53324 if((!c.titlebar && !c.title) || c.titlebar === false){
53325 this.titleEl.hide();
53327 this.titleEl.show();
53329 this.titleTextEl.innerHTML = c.title;
53333 this.duration = c.duration || .30;
53334 this.slideDuration = c.slideDuration || .45;
53337 this.collapse(true);
53344 * Returns true if this region is currently visible.
53345 * @return {Boolean}
53347 isVisible : function(){
53348 return this.visible;
53352 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53353 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53355 setCollapsedTitle : function(title){
53356 title = title || " ";
53357 if(this.collapsedTitleTextEl){
53358 this.collapsedTitleTextEl.innerHTML = title;
53362 getBox : function(){
53364 if(!this.collapsed){
53365 b = this.el.getBox(false, true);
53367 b = this.collapsedEl.getBox(false, true);
53372 getMargins : function(){
53373 return this.collapsed ? this.cmargins : this.margins;
53376 highlight : function(){
53377 this.el.addClass("x-layout-panel-dragover");
53380 unhighlight : function(){
53381 this.el.removeClass("x-layout-panel-dragover");
53384 updateBox : function(box){
53386 if(!this.collapsed){
53387 this.el.dom.style.left = box.x + "px";
53388 this.el.dom.style.top = box.y + "px";
53389 this.updateBody(box.width, box.height);
53391 this.collapsedEl.dom.style.left = box.x + "px";
53392 this.collapsedEl.dom.style.top = box.y + "px";
53393 this.collapsedEl.setSize(box.width, box.height);
53396 this.tabs.autoSizeTabs();
53400 updateBody : function(w, h){
53402 this.el.setWidth(w);
53403 w -= this.el.getBorderWidth("rl");
53404 if(this.config.adjustments){
53405 w += this.config.adjustments[0];
53409 this.el.setHeight(h);
53410 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53411 h -= this.el.getBorderWidth("tb");
53412 if(this.config.adjustments){
53413 h += this.config.adjustments[1];
53415 this.bodyEl.setHeight(h);
53417 h = this.tabs.syncHeight(h);
53420 if(this.panelSize){
53421 w = w !== null ? w : this.panelSize.width;
53422 h = h !== null ? h : this.panelSize.height;
53424 if(this.activePanel){
53425 var el = this.activePanel.getEl();
53426 w = w !== null ? w : el.getWidth();
53427 h = h !== null ? h : el.getHeight();
53428 this.panelSize = {width: w, height: h};
53429 this.activePanel.setSize(w, h);
53431 if(Roo.isIE && this.tabs){
53432 this.tabs.el.repaint();
53437 * Returns the container element for this region.
53438 * @return {Roo.Element}
53440 getEl : function(){
53445 * Hides this region.
53448 if(!this.collapsed){
53449 this.el.dom.style.left = "-2000px";
53452 this.collapsedEl.dom.style.left = "-2000px";
53453 this.collapsedEl.hide();
53455 this.visible = false;
53456 this.fireEvent("visibilitychange", this, false);
53460 * Shows this region if it was previously hidden.
53463 if(!this.collapsed){
53466 this.collapsedEl.show();
53468 this.visible = true;
53469 this.fireEvent("visibilitychange", this, true);
53472 closeClicked : function(){
53473 if(this.activePanel){
53474 this.remove(this.activePanel);
53478 collapseClick : function(e){
53480 e.stopPropagation();
53483 e.stopPropagation();
53489 * Collapses this region.
53490 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53492 collapse : function(skipAnim, skipCheck){
53493 if(this.collapsed) {
53497 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53499 this.collapsed = true;
53501 this.split.el.hide();
53503 if(this.config.animate && skipAnim !== true){
53504 this.fireEvent("invalidated", this);
53505 this.animateCollapse();
53507 this.el.setLocation(-20000,-20000);
53509 this.collapsedEl.show();
53510 this.fireEvent("collapsed", this);
53511 this.fireEvent("invalidated", this);
53517 animateCollapse : function(){
53522 * Expands this region if it was previously collapsed.
53523 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53524 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53526 expand : function(e, skipAnim){
53528 e.stopPropagation();
53530 if(!this.collapsed || this.el.hasActiveFx()) {
53534 this.afterSlideIn();
53537 this.collapsed = false;
53538 if(this.config.animate && skipAnim !== true){
53539 this.animateExpand();
53543 this.split.el.show();
53545 this.collapsedEl.setLocation(-2000,-2000);
53546 this.collapsedEl.hide();
53547 this.fireEvent("invalidated", this);
53548 this.fireEvent("expanded", this);
53552 animateExpand : function(){
53556 initTabs : function()
53558 this.bodyEl.setStyle("overflow", "hidden");
53559 var ts = new Roo.TabPanel(
53562 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53563 disableTooltips: this.config.disableTabTips,
53564 toolbar : this.config.toolbar
53567 if(this.config.hideTabs){
53568 ts.stripWrap.setDisplayed(false);
53571 ts.resizeTabs = this.config.resizeTabs === true;
53572 ts.minTabWidth = this.config.minTabWidth || 40;
53573 ts.maxTabWidth = this.config.maxTabWidth || 250;
53574 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53575 ts.monitorResize = false;
53576 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53577 ts.bodyEl.addClass('x-layout-tabs-body');
53578 this.panels.each(this.initPanelAsTab, this);
53581 initPanelAsTab : function(panel){
53582 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53583 this.config.closeOnTab && panel.isClosable());
53584 if(panel.tabTip !== undefined){
53585 ti.setTooltip(panel.tabTip);
53587 ti.on("activate", function(){
53588 this.setActivePanel(panel);
53590 if(this.config.closeOnTab){
53591 ti.on("beforeclose", function(t, e){
53593 this.remove(panel);
53599 updatePanelTitle : function(panel, title){
53600 if(this.activePanel == panel){
53601 this.updateTitle(title);
53604 var ti = this.tabs.getTab(panel.getEl().id);
53606 if(panel.tabTip !== undefined){
53607 ti.setTooltip(panel.tabTip);
53612 updateTitle : function(title){
53613 if(this.titleTextEl && !this.config.title){
53614 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53618 setActivePanel : function(panel){
53619 panel = this.getPanel(panel);
53620 if(this.activePanel && this.activePanel != panel){
53621 this.activePanel.setActiveState(false);
53623 this.activePanel = panel;
53624 panel.setActiveState(true);
53625 if(this.panelSize){
53626 panel.setSize(this.panelSize.width, this.panelSize.height);
53629 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53631 this.updateTitle(panel.getTitle());
53633 this.fireEvent("invalidated", this);
53635 this.fireEvent("panelactivated", this, panel);
53639 * Shows the specified panel.
53640 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53641 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53643 showPanel : function(panel)
53645 panel = this.getPanel(panel);
53648 var tab = this.tabs.getTab(panel.getEl().id);
53649 if(tab.isHidden()){
53650 this.tabs.unhideTab(tab.id);
53654 this.setActivePanel(panel);
53661 * Get the active panel for this region.
53662 * @return {Roo.ContentPanel} The active panel or null
53664 getActivePanel : function(){
53665 return this.activePanel;
53668 validateVisibility : function(){
53669 if(this.panels.getCount() < 1){
53670 this.updateTitle(" ");
53671 this.closeBtn.hide();
53674 if(!this.isVisible()){
53681 * Adds the passed ContentPanel(s) to this region.
53682 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53683 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53685 add : function(panel){
53686 if(arguments.length > 1){
53687 for(var i = 0, len = arguments.length; i < len; i++) {
53688 this.add(arguments[i]);
53692 if(this.hasPanel(panel)){
53693 this.showPanel(panel);
53696 panel.setRegion(this);
53697 this.panels.add(panel);
53698 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53699 this.bodyEl.dom.appendChild(panel.getEl().dom);
53700 if(panel.background !== true){
53701 this.setActivePanel(panel);
53703 this.fireEvent("paneladded", this, panel);
53709 this.initPanelAsTab(panel);
53711 if(panel.background !== true){
53712 this.tabs.activate(panel.getEl().id);
53714 this.fireEvent("paneladded", this, panel);
53719 * Hides the tab for the specified panel.
53720 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53722 hidePanel : function(panel){
53723 if(this.tabs && (panel = this.getPanel(panel))){
53724 this.tabs.hideTab(panel.getEl().id);
53729 * Unhides the tab for a previously hidden panel.
53730 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53732 unhidePanel : function(panel){
53733 if(this.tabs && (panel = this.getPanel(panel))){
53734 this.tabs.unhideTab(panel.getEl().id);
53738 clearPanels : function(){
53739 while(this.panels.getCount() > 0){
53740 this.remove(this.panels.first());
53745 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53746 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53747 * @param {Boolean} preservePanel Overrides the config preservePanel option
53748 * @return {Roo.ContentPanel} The panel that was removed
53750 remove : function(panel, preservePanel){
53751 panel = this.getPanel(panel);
53756 this.fireEvent("beforeremove", this, panel, e);
53757 if(e.cancel === true){
53760 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53761 var panelId = panel.getId();
53762 this.panels.removeKey(panelId);
53764 document.body.appendChild(panel.getEl().dom);
53767 this.tabs.removeTab(panel.getEl().id);
53768 }else if (!preservePanel){
53769 this.bodyEl.dom.removeChild(panel.getEl().dom);
53771 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53772 var p = this.panels.first();
53773 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53774 tempEl.appendChild(p.getEl().dom);
53775 this.bodyEl.update("");
53776 this.bodyEl.dom.appendChild(p.getEl().dom);
53778 this.updateTitle(p.getTitle());
53780 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53781 this.setActivePanel(p);
53783 panel.setRegion(null);
53784 if(this.activePanel == panel){
53785 this.activePanel = null;
53787 if(this.config.autoDestroy !== false && preservePanel !== true){
53788 try{panel.destroy();}catch(e){}
53790 this.fireEvent("panelremoved", this, panel);
53795 * Returns the TabPanel component used by this region
53796 * @return {Roo.TabPanel}
53798 getTabs : function(){
53802 createTool : function(parentEl, className){
53803 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53804 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53805 btn.addClassOnOver("x-layout-tools-button-over");
53810 * Ext JS Library 1.1.1
53811 * Copyright(c) 2006-2007, Ext JS, LLC.
53813 * Originally Released Under LGPL - original licence link has changed is not relivant.
53816 * <script type="text/javascript">
53822 * @class Roo.SplitLayoutRegion
53823 * @extends Roo.LayoutRegion
53824 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53826 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53827 this.cursor = cursor;
53828 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53831 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53832 splitTip : "Drag to resize.",
53833 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53834 useSplitTips : false,
53836 applyConfig : function(config){
53837 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53840 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53841 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53842 /** The SplitBar for this region
53843 * @type Roo.SplitBar */
53844 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53845 this.split.on("moved", this.onSplitMove, this);
53846 this.split.useShim = config.useShim === true;
53847 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53848 if(this.useSplitTips){
53849 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53851 if(config.collapsible){
53852 this.split.el.on("dblclick", this.collapse, this);
53855 if(typeof config.minSize != "undefined"){
53856 this.split.minSize = config.minSize;
53858 if(typeof config.maxSize != "undefined"){
53859 this.split.maxSize = config.maxSize;
53861 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53862 this.hideSplitter();
53867 getHMaxSize : function(){
53868 var cmax = this.config.maxSize || 10000;
53869 var center = this.mgr.getRegion("center");
53870 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53873 getVMaxSize : function(){
53874 var cmax = this.config.maxSize || 10000;
53875 var center = this.mgr.getRegion("center");
53876 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53879 onSplitMove : function(split, newSize){
53880 this.fireEvent("resized", this, newSize);
53884 * Returns the {@link Roo.SplitBar} for this region.
53885 * @return {Roo.SplitBar}
53887 getSplitBar : function(){
53892 this.hideSplitter();
53893 Roo.SplitLayoutRegion.superclass.hide.call(this);
53896 hideSplitter : function(){
53898 this.split.el.setLocation(-2000,-2000);
53899 this.split.el.hide();
53905 this.split.el.show();
53907 Roo.SplitLayoutRegion.superclass.show.call(this);
53910 beforeSlide: function(){
53911 if(Roo.isGecko){// firefox overflow auto bug workaround
53912 this.bodyEl.clip();
53914 this.tabs.bodyEl.clip();
53916 if(this.activePanel){
53917 this.activePanel.getEl().clip();
53919 if(this.activePanel.beforeSlide){
53920 this.activePanel.beforeSlide();
53926 afterSlide : function(){
53927 if(Roo.isGecko){// firefox overflow auto bug workaround
53928 this.bodyEl.unclip();
53930 this.tabs.bodyEl.unclip();
53932 if(this.activePanel){
53933 this.activePanel.getEl().unclip();
53934 if(this.activePanel.afterSlide){
53935 this.activePanel.afterSlide();
53941 initAutoHide : function(){
53942 if(this.autoHide !== false){
53943 if(!this.autoHideHd){
53944 var st = new Roo.util.DelayedTask(this.slideIn, this);
53945 this.autoHideHd = {
53946 "mouseout": function(e){
53947 if(!e.within(this.el, true)){
53951 "mouseover" : function(e){
53957 this.el.on(this.autoHideHd);
53961 clearAutoHide : function(){
53962 if(this.autoHide !== false){
53963 this.el.un("mouseout", this.autoHideHd.mouseout);
53964 this.el.un("mouseover", this.autoHideHd.mouseover);
53968 clearMonitor : function(){
53969 Roo.get(document).un("click", this.slideInIf, this);
53972 // these names are backwards but not changed for compat
53973 slideOut : function(){
53974 if(this.isSlid || this.el.hasActiveFx()){
53977 this.isSlid = true;
53978 if(this.collapseBtn){
53979 this.collapseBtn.hide();
53981 this.closeBtnState = this.closeBtn.getStyle('display');
53982 this.closeBtn.hide();
53984 this.stickBtn.show();
53987 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53988 this.beforeSlide();
53989 this.el.setStyle("z-index", 10001);
53990 this.el.slideIn(this.getSlideAnchor(), {
53991 callback: function(){
53993 this.initAutoHide();
53994 Roo.get(document).on("click", this.slideInIf, this);
53995 this.fireEvent("slideshow", this);
54002 afterSlideIn : function(){
54003 this.clearAutoHide();
54004 this.isSlid = false;
54005 this.clearMonitor();
54006 this.el.setStyle("z-index", "");
54007 if(this.collapseBtn){
54008 this.collapseBtn.show();
54010 this.closeBtn.setStyle('display', this.closeBtnState);
54012 this.stickBtn.hide();
54014 this.fireEvent("slidehide", this);
54017 slideIn : function(cb){
54018 if(!this.isSlid || this.el.hasActiveFx()){
54022 this.isSlid = false;
54023 this.beforeSlide();
54024 this.el.slideOut(this.getSlideAnchor(), {
54025 callback: function(){
54026 this.el.setLeftTop(-10000, -10000);
54028 this.afterSlideIn();
54036 slideInIf : function(e){
54037 if(!e.within(this.el)){
54042 animateCollapse : function(){
54043 this.beforeSlide();
54044 this.el.setStyle("z-index", 20000);
54045 var anchor = this.getSlideAnchor();
54046 this.el.slideOut(anchor, {
54047 callback : function(){
54048 this.el.setStyle("z-index", "");
54049 this.collapsedEl.slideIn(anchor, {duration:.3});
54051 this.el.setLocation(-10000,-10000);
54053 this.fireEvent("collapsed", this);
54060 animateExpand : function(){
54061 this.beforeSlide();
54062 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
54063 this.el.setStyle("z-index", 20000);
54064 this.collapsedEl.hide({
54067 this.el.slideIn(this.getSlideAnchor(), {
54068 callback : function(){
54069 this.el.setStyle("z-index", "");
54072 this.split.el.show();
54074 this.fireEvent("invalidated", this);
54075 this.fireEvent("expanded", this);
54103 getAnchor : function(){
54104 return this.anchors[this.position];
54107 getCollapseAnchor : function(){
54108 return this.canchors[this.position];
54111 getSlideAnchor : function(){
54112 return this.sanchors[this.position];
54115 getAlignAdj : function(){
54116 var cm = this.cmargins;
54117 switch(this.position){
54133 getExpandAdj : function(){
54134 var c = this.collapsedEl, cm = this.cmargins;
54135 switch(this.position){
54137 return [-(cm.right+c.getWidth()+cm.left), 0];
54140 return [cm.right+c.getWidth()+cm.left, 0];
54143 return [0, -(cm.top+cm.bottom+c.getHeight())];
54146 return [0, cm.top+cm.bottom+c.getHeight()];
54152 * Ext JS Library 1.1.1
54153 * Copyright(c) 2006-2007, Ext JS, LLC.
54155 * Originally Released Under LGPL - original licence link has changed is not relivant.
54158 * <script type="text/javascript">
54161 * These classes are private internal classes
54163 Roo.CenterLayoutRegion = function(mgr, config){
54164 Roo.LayoutRegion.call(this, mgr, config, "center");
54165 this.visible = true;
54166 this.minWidth = config.minWidth || 20;
54167 this.minHeight = config.minHeight || 20;
54170 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
54172 // center panel can't be hidden
54176 // center panel can't be hidden
54179 getMinWidth: function(){
54180 return this.minWidth;
54183 getMinHeight: function(){
54184 return this.minHeight;
54189 Roo.NorthLayoutRegion = function(mgr, config){
54190 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
54192 this.split.placement = Roo.SplitBar.TOP;
54193 this.split.orientation = Roo.SplitBar.VERTICAL;
54194 this.split.el.addClass("x-layout-split-v");
54196 var size = config.initialSize || config.height;
54197 if(typeof size != "undefined"){
54198 this.el.setHeight(size);
54201 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
54202 orientation: Roo.SplitBar.VERTICAL,
54203 getBox : function(){
54204 if(this.collapsed){
54205 return this.collapsedEl.getBox();
54207 var box = this.el.getBox();
54209 box.height += this.split.el.getHeight();
54214 updateBox : function(box){
54215 if(this.split && !this.collapsed){
54216 box.height -= this.split.el.getHeight();
54217 this.split.el.setLeft(box.x);
54218 this.split.el.setTop(box.y+box.height);
54219 this.split.el.setWidth(box.width);
54221 if(this.collapsed){
54222 this.updateBody(box.width, null);
54224 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54228 Roo.SouthLayoutRegion = function(mgr, config){
54229 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
54231 this.split.placement = Roo.SplitBar.BOTTOM;
54232 this.split.orientation = Roo.SplitBar.VERTICAL;
54233 this.split.el.addClass("x-layout-split-v");
54235 var size = config.initialSize || config.height;
54236 if(typeof size != "undefined"){
54237 this.el.setHeight(size);
54240 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
54241 orientation: Roo.SplitBar.VERTICAL,
54242 getBox : function(){
54243 if(this.collapsed){
54244 return this.collapsedEl.getBox();
54246 var box = this.el.getBox();
54248 var sh = this.split.el.getHeight();
54255 updateBox : function(box){
54256 if(this.split && !this.collapsed){
54257 var sh = this.split.el.getHeight();
54260 this.split.el.setLeft(box.x);
54261 this.split.el.setTop(box.y-sh);
54262 this.split.el.setWidth(box.width);
54264 if(this.collapsed){
54265 this.updateBody(box.width, null);
54267 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54271 Roo.EastLayoutRegion = function(mgr, config){
54272 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54274 this.split.placement = Roo.SplitBar.RIGHT;
54275 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54276 this.split.el.addClass("x-layout-split-h");
54278 var size = config.initialSize || config.width;
54279 if(typeof size != "undefined"){
54280 this.el.setWidth(size);
54283 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54284 orientation: Roo.SplitBar.HORIZONTAL,
54285 getBox : function(){
54286 if(this.collapsed){
54287 return this.collapsedEl.getBox();
54289 var box = this.el.getBox();
54291 var sw = this.split.el.getWidth();
54298 updateBox : function(box){
54299 if(this.split && !this.collapsed){
54300 var sw = this.split.el.getWidth();
54302 this.split.el.setLeft(box.x);
54303 this.split.el.setTop(box.y);
54304 this.split.el.setHeight(box.height);
54307 if(this.collapsed){
54308 this.updateBody(null, box.height);
54310 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54314 Roo.WestLayoutRegion = function(mgr, config){
54315 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54317 this.split.placement = Roo.SplitBar.LEFT;
54318 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54319 this.split.el.addClass("x-layout-split-h");
54321 var size = config.initialSize || config.width;
54322 if(typeof size != "undefined"){
54323 this.el.setWidth(size);
54326 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
54327 orientation: Roo.SplitBar.HORIZONTAL,
54328 getBox : function(){
54329 if(this.collapsed){
54330 return this.collapsedEl.getBox();
54332 var box = this.el.getBox();
54334 box.width += this.split.el.getWidth();
54339 updateBox : function(box){
54340 if(this.split && !this.collapsed){
54341 var sw = this.split.el.getWidth();
54343 this.split.el.setLeft(box.x+box.width);
54344 this.split.el.setTop(box.y);
54345 this.split.el.setHeight(box.height);
54347 if(this.collapsed){
54348 this.updateBody(null, box.height);
54350 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54355 * Ext JS Library 1.1.1
54356 * Copyright(c) 2006-2007, Ext JS, LLC.
54358 * Originally Released Under LGPL - original licence link has changed is not relivant.
54361 * <script type="text/javascript">
54366 * Private internal class for reading and applying state
54368 Roo.LayoutStateManager = function(layout){
54369 // default empty state
54378 Roo.LayoutStateManager.prototype = {
54379 init : function(layout, provider){
54380 this.provider = provider;
54381 var state = provider.get(layout.id+"-layout-state");
54383 var wasUpdating = layout.isUpdating();
54385 layout.beginUpdate();
54387 for(var key in state){
54388 if(typeof state[key] != "function"){
54389 var rstate = state[key];
54390 var r = layout.getRegion(key);
54393 r.resizeTo(rstate.size);
54395 if(rstate.collapsed == true){
54398 r.expand(null, true);
54404 layout.endUpdate();
54406 this.state = state;
54408 this.layout = layout;
54409 layout.on("regionresized", this.onRegionResized, this);
54410 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54411 layout.on("regionexpanded", this.onRegionExpanded, this);
54414 storeState : function(){
54415 this.provider.set(this.layout.id+"-layout-state", this.state);
54418 onRegionResized : function(region, newSize){
54419 this.state[region.getPosition()].size = newSize;
54423 onRegionCollapsed : function(region){
54424 this.state[region.getPosition()].collapsed = true;
54428 onRegionExpanded : function(region){
54429 this.state[region.getPosition()].collapsed = false;
54434 * Ext JS Library 1.1.1
54435 * Copyright(c) 2006-2007, Ext JS, LLC.
54437 * Originally Released Under LGPL - original licence link has changed is not relivant.
54440 * <script type="text/javascript">
54443 * @class Roo.ContentPanel
54444 * @extends Roo.util.Observable
54445 * @children Roo.form.Form Roo.JsonView Roo.View
54446 * @parent Roo.BorderLayout Roo.LayoutDialog builder-top
54447 * A basic ContentPanel element.
54448 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54449 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54450 * @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
54451 * @cfg {Boolean} closable True if the panel can be closed/removed
54452 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54453 * @cfg {String|HTMLElement|Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54454 * @cfg {Roo.Toolbar} toolbar A toolbar for this panel
54455 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54456 * @cfg {String} title The title for this panel
54457 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54458 * @cfg {String} url Calls {@link #setUrl} with this value
54459 * @cfg {String} region [required] (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54460 * @cfg {String|Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54461 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54462 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54463 * @cfg {String} style Extra style to add to the content panel
54464 * @cfg {Roo.menu.Menu} menu popup menu
54467 * Create a new ContentPanel.
54468 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54469 * @param {String/Object} config A string to set only the title or a config object
54470 * @param {String} content (optional) Set the HTML content for this panel
54471 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54473 Roo.ContentPanel = function(el, config, content){
54477 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54481 if (config && config.parentLayout) {
54482 el = config.parentLayout.el.createChild();
54485 if(el.autoCreate){ // xtype is available if this is called from factory
54489 this.el = Roo.get(el);
54490 if(!this.el && config && config.autoCreate){
54491 if(typeof config.autoCreate == "object"){
54492 if(!config.autoCreate.id){
54493 config.autoCreate.id = config.id||el;
54495 this.el = Roo.DomHelper.append(document.body,
54496 config.autoCreate, true);
54498 this.el = Roo.DomHelper.append(document.body,
54499 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54504 this.closable = false;
54505 this.loaded = false;
54506 this.active = false;
54507 if(typeof config == "string"){
54508 this.title = config;
54510 Roo.apply(this, config);
54513 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54514 this.wrapEl = this.el.wrap();
54515 this.toolbar.container = this.el.insertSibling(false, 'before');
54516 this.toolbar = new Roo.Toolbar(this.toolbar);
54519 // xtype created footer. - not sure if will work as we normally have to render first..
54520 if (this.footer && !this.footer.el && this.footer.xtype) {
54521 if (!this.wrapEl) {
54522 this.wrapEl = this.el.wrap();
54525 this.footer.container = this.wrapEl.createChild();
54527 this.footer = Roo.factory(this.footer, Roo);
54532 this.resizeEl = Roo.get(this.resizeEl, true);
54534 this.resizeEl = this.el;
54536 // handle view.xtype
54544 * Fires when this panel is activated.
54545 * @param {Roo.ContentPanel} this
54549 * @event deactivate
54550 * Fires when this panel is activated.
54551 * @param {Roo.ContentPanel} this
54553 "deactivate" : true,
54557 * Fires when this panel is resized if fitToFrame is true.
54558 * @param {Roo.ContentPanel} this
54559 * @param {Number} width The width after any component adjustments
54560 * @param {Number} height The height after any component adjustments
54566 * Fires when this tab is created
54567 * @param {Roo.ContentPanel} this
54577 if(this.autoScroll){
54578 this.resizeEl.setStyle("overflow", "auto");
54580 // fix randome scrolling
54581 this.el.on('scroll', function() {
54582 Roo.log('fix random scolling');
54583 this.scrollTo('top',0);
54586 content = content || this.content;
54588 this.setContent(content);
54590 if(config && config.url){
54591 this.setUrl(this.url, this.params, this.loadOnce);
54596 Roo.ContentPanel.superclass.constructor.call(this);
54598 if (this.view && typeof(this.view.xtype) != 'undefined') {
54599 this.view.el = this.el.appendChild(document.createElement("div"));
54600 this.view = Roo.factory(this.view);
54601 this.view.render && this.view.render(false, '');
54605 this.fireEvent('render', this);
54608 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54610 setRegion : function(region){
54611 this.region = region;
54613 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54615 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54620 * Returns the toolbar for this Panel if one was configured.
54621 * @return {Roo.Toolbar}
54623 getToolbar : function(){
54624 return this.toolbar;
54627 setActiveState : function(active){
54628 this.active = active;
54630 this.fireEvent("deactivate", this);
54632 this.fireEvent("activate", this);
54636 * Updates this panel's element
54637 * @param {String} content The new content
54638 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54640 setContent : function(content, loadScripts){
54641 this.el.update(content, loadScripts);
54644 ignoreResize : function(w, h){
54645 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54648 this.lastSize = {width: w, height: h};
54653 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54654 * @return {Roo.UpdateManager} The UpdateManager
54656 getUpdateManager : function(){
54657 return this.el.getUpdateManager();
54660 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54661 * @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:
54664 url: "your-url.php",
54665 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54666 callback: yourFunction,
54667 scope: yourObject, //(optional scope)
54670 text: "Loading...",
54675 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54676 * 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.
54677 * @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}
54678 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54679 * @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.
54680 * @return {Roo.ContentPanel} this
54683 var um = this.el.getUpdateManager();
54684 um.update.apply(um, arguments);
54690 * 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.
54691 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54692 * @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)
54693 * @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)
54694 * @return {Roo.UpdateManager} The UpdateManager
54696 setUrl : function(url, params, loadOnce){
54697 if(this.refreshDelegate){
54698 this.removeListener("activate", this.refreshDelegate);
54700 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54701 this.on("activate", this.refreshDelegate);
54702 return this.el.getUpdateManager();
54705 _handleRefresh : function(url, params, loadOnce){
54706 if(!loadOnce || !this.loaded){
54707 var updater = this.el.getUpdateManager();
54708 updater.update(url, params, this._setLoaded.createDelegate(this));
54712 _setLoaded : function(){
54713 this.loaded = true;
54717 * Returns this panel's id
54720 getId : function(){
54725 * Returns this panel's element - used by regiosn to add.
54726 * @return {Roo.Element}
54728 getEl : function(){
54729 return this.wrapEl || this.el;
54732 adjustForComponents : function(width, height)
54734 //Roo.log('adjustForComponents ');
54735 if(this.resizeEl != this.el){
54736 width -= this.el.getFrameWidth('lr');
54737 height -= this.el.getFrameWidth('tb');
54740 var te = this.toolbar.getEl();
54741 height -= te.getHeight();
54742 te.setWidth(width);
54745 var te = this.footer.getEl();
54746 //Roo.log("footer:" + te.getHeight());
54748 height -= te.getHeight();
54749 te.setWidth(width);
54753 if(this.adjustments){
54754 width += this.adjustments[0];
54755 height += this.adjustments[1];
54757 return {"width": width, "height": height};
54760 setSize : function(width, height){
54761 if(this.fitToFrame && !this.ignoreResize(width, height)){
54762 if(this.fitContainer && this.resizeEl != this.el){
54763 this.el.setSize(width, height);
54765 var size = this.adjustForComponents(width, height);
54766 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54767 this.fireEvent('resize', this, size.width, size.height);
54772 * Returns this panel's title
54775 getTitle : function(){
54780 * Set this panel's title
54781 * @param {String} title
54783 setTitle : function(title){
54784 this.title = title;
54786 this.region.updatePanelTitle(this, title);
54791 * Returns true is this panel was configured to be closable
54792 * @return {Boolean}
54794 isClosable : function(){
54795 return this.closable;
54798 beforeSlide : function(){
54800 this.resizeEl.clip();
54803 afterSlide : function(){
54805 this.resizeEl.unclip();
54809 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54810 * Will fail silently if the {@link #setUrl} method has not been called.
54811 * This does not activate the panel, just updates its content.
54813 refresh : function(){
54814 if(this.refreshDelegate){
54815 this.loaded = false;
54816 this.refreshDelegate();
54821 * Destroys this panel
54823 destroy : function(){
54824 this.el.removeAllListeners();
54825 var tempEl = document.createElement("span");
54826 tempEl.appendChild(this.el.dom);
54827 tempEl.innerHTML = "";
54833 * form - if the content panel contains a form - this is a reference to it.
54834 * @type {Roo.form.Form}
54838 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54839 * This contains a reference to it.
54845 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54855 * @param {Object} cfg Xtype definition of item to add.
54858 addxtype : function(cfg) {
54860 if (cfg.xtype.match(/^Form$/)) {
54863 //if (this.footer) {
54864 // el = this.footer.container.insertSibling(false, 'before');
54866 el = this.el.createChild();
54869 this.form = new Roo.form.Form(cfg);
54872 if ( this.form.allItems.length) {
54873 this.form.render(el.dom);
54877 // should only have one of theses..
54878 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54879 // views.. should not be just added - used named prop 'view''
54881 cfg.el = this.el.appendChild(document.createElement("div"));
54884 var ret = new Roo.factory(cfg);
54886 ret.render && ret.render(false, ''); // render blank..
54895 * @class Roo.GridPanel
54896 * @extends Roo.ContentPanel
54898 * Create a new GridPanel.
54899 * @param {Roo.grid.Grid} grid The grid for this panel
54900 * @param {String/Object} config A string to set only the panel's title, or a config object
54902 Roo.GridPanel = function(grid, config){
54905 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54906 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54908 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54910 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54913 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54915 // xtype created footer. - not sure if will work as we normally have to render first..
54916 if (this.footer && !this.footer.el && this.footer.xtype) {
54918 this.footer.container = this.grid.getView().getFooterPanel(true);
54919 this.footer.dataSource = this.grid.dataSource;
54920 this.footer = Roo.factory(this.footer, Roo);
54924 grid.monitorWindowResize = false; // turn off autosizing
54925 grid.autoHeight = false;
54926 grid.autoWidth = false;
54928 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54931 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54932 getId : function(){
54933 return this.grid.id;
54937 * Returns the grid for this panel
54938 * @return {Roo.grid.Grid}
54940 getGrid : function(){
54944 setSize : function(width, height){
54945 if(!this.ignoreResize(width, height)){
54946 var grid = this.grid;
54947 var size = this.adjustForComponents(width, height);
54948 grid.getGridEl().setSize(size.width, size.height);
54953 beforeSlide : function(){
54954 this.grid.getView().scroller.clip();
54957 afterSlide : function(){
54958 this.grid.getView().scroller.unclip();
54961 destroy : function(){
54962 this.grid.destroy();
54964 Roo.GridPanel.superclass.destroy.call(this);
54970 * @class Roo.NestedLayoutPanel
54971 * @extends Roo.ContentPanel
54973 * Create a new NestedLayoutPanel.
54976 * @param {Roo.BorderLayout} layout [required] The layout for this panel
54977 * @param {String/Object} config A string to set only the title or a config object
54979 Roo.NestedLayoutPanel = function(layout, config)
54981 // construct with only one argument..
54982 /* FIXME - implement nicer consturctors
54983 if (layout.layout) {
54985 layout = config.layout;
54986 delete config.layout;
54988 if (layout.xtype && !layout.getEl) {
54989 // then layout needs constructing..
54990 layout = Roo.factory(layout, Roo);
54995 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54997 layout.monitorWindowResize = false; // turn off autosizing
54998 this.layout = layout;
54999 this.layout.getEl().addClass("x-layout-nested-layout");
55006 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
55008 setSize : function(width, height){
55009 if(!this.ignoreResize(width, height)){
55010 var size = this.adjustForComponents(width, height);
55011 var el = this.layout.getEl();
55012 el.setSize(size.width, size.height);
55013 var touch = el.dom.offsetWidth;
55014 this.layout.layout();
55015 // ie requires a double layout on the first pass
55016 if(Roo.isIE && !this.initialized){
55017 this.initialized = true;
55018 this.layout.layout();
55023 // activate all subpanels if not currently active..
55025 setActiveState : function(active){
55026 this.active = active;
55028 this.fireEvent("deactivate", this);
55032 this.fireEvent("activate", this);
55033 // not sure if this should happen before or after..
55034 if (!this.layout) {
55035 return; // should not happen..
55038 for (var r in this.layout.regions) {
55039 reg = this.layout.getRegion(r);
55040 if (reg.getActivePanel()) {
55041 //reg.showPanel(reg.getActivePanel()); // force it to activate..
55042 reg.setActivePanel(reg.getActivePanel());
55045 if (!reg.panels.length) {
55048 reg.showPanel(reg.getPanel(0));
55057 * Returns the nested BorderLayout for this panel
55058 * @return {Roo.BorderLayout}
55060 getLayout : function(){
55061 return this.layout;
55065 * Adds a xtype elements to the layout of the nested panel
55069 xtype : 'ContentPanel',
55076 xtype : 'NestedLayoutPanel',
55082 items : [ ... list of content panels or nested layout panels.. ]
55086 * @param {Object} cfg Xtype definition of item to add.
55088 addxtype : function(cfg) {
55089 return this.layout.addxtype(cfg);
55094 Roo.ScrollPanel = function(el, config, content){
55095 config = config || {};
55096 config.fitToFrame = true;
55097 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
55099 this.el.dom.style.overflow = "hidden";
55100 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
55101 this.el.removeClass("x-layout-inactive-content");
55102 this.el.on("mousewheel", this.onWheel, this);
55104 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
55105 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
55106 up.unselectable(); down.unselectable();
55107 up.on("click", this.scrollUp, this);
55108 down.on("click", this.scrollDown, this);
55109 up.addClassOnOver("x-scroller-btn-over");
55110 down.addClassOnOver("x-scroller-btn-over");
55111 up.addClassOnClick("x-scroller-btn-click");
55112 down.addClassOnClick("x-scroller-btn-click");
55113 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
55115 this.resizeEl = this.el;
55116 this.el = wrap; this.up = up; this.down = down;
55119 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
55121 wheelIncrement : 5,
55122 scrollUp : function(){
55123 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
55126 scrollDown : function(){
55127 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
55130 afterScroll : function(){
55131 var el = this.resizeEl;
55132 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
55133 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
55134 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
55137 setSize : function(){
55138 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
55139 this.afterScroll();
55142 onWheel : function(e){
55143 var d = e.getWheelDelta();
55144 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
55145 this.afterScroll();
55149 setContent : function(content, loadScripts){
55150 this.resizeEl.update(content, loadScripts);
55158 * @class Roo.TreePanel
55159 * @extends Roo.ContentPanel
55160 * Treepanel component
55163 * Create a new TreePanel. - defaults to fit/scoll contents.
55164 * @param {String/Object} config A string to set only the panel's title, or a config object
55166 Roo.TreePanel = function(config){
55167 var el = config.el;
55168 var tree = config.tree;
55169 delete config.tree;
55170 delete config.el; // hopefull!
55172 // wrapper for IE7 strict & safari scroll issue
55174 var treeEl = el.createChild();
55175 config.resizeEl = treeEl;
55179 Roo.TreePanel.superclass.constructor.call(this, el, config);
55182 this.tree = new Roo.tree.TreePanel(treeEl , tree);
55183 //console.log(tree);
55184 this.on('activate', function()
55186 if (this.tree.rendered) {
55189 //console.log('render tree');
55190 this.tree.render();
55192 // this should not be needed.. - it's actually the 'el' that resizes?
55193 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
55195 //this.on('resize', function (cp, w, h) {
55196 // this.tree.innerCt.setWidth(w);
55197 // this.tree.innerCt.setHeight(h);
55198 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
55205 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
55209 * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
55227 * Ext JS Library 1.1.1
55228 * Copyright(c) 2006-2007, Ext JS, LLC.
55230 * Originally Released Under LGPL - original licence link has changed is not relivant.
55233 * <script type="text/javascript">
55238 * @class Roo.ReaderLayout
55239 * @extends Roo.BorderLayout
55240 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
55241 * center region containing two nested regions (a top one for a list view and one for item preview below),
55242 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
55243 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
55244 * expedites the setup of the overall layout and regions for this common application style.
55247 var reader = new Roo.ReaderLayout();
55248 var CP = Roo.ContentPanel; // shortcut for adding
55250 reader.beginUpdate();
55251 reader.add("north", new CP("north", "North"));
55252 reader.add("west", new CP("west", {title: "West"}));
55253 reader.add("east", new CP("east", {title: "East"}));
55255 reader.regions.listView.add(new CP("listView", "List"));
55256 reader.regions.preview.add(new CP("preview", "Preview"));
55257 reader.endUpdate();
55260 * Create a new ReaderLayout
55261 * @param {Object} config Configuration options
55262 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55263 * document.body if omitted)
55265 Roo.ReaderLayout = function(config, renderTo){
55266 var c = config || {size:{}};
55267 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55268 north: c.north !== false ? Roo.apply({
55272 }, c.north) : false,
55273 west: c.west !== false ? Roo.apply({
55281 margins:{left:5,right:0,bottom:5,top:5},
55282 cmargins:{left:5,right:5,bottom:5,top:5}
55283 }, c.west) : false,
55284 east: c.east !== false ? Roo.apply({
55292 margins:{left:0,right:5,bottom:5,top:5},
55293 cmargins:{left:5,right:5,bottom:5,top:5}
55294 }, c.east) : false,
55295 center: Roo.apply({
55296 tabPosition: 'top',
55300 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55304 this.el.addClass('x-reader');
55306 this.beginUpdate();
55308 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55309 south: c.preview !== false ? Roo.apply({
55316 cmargins:{top:5,left:0, right:0, bottom:0}
55317 }, c.preview) : false,
55318 center: Roo.apply({
55324 this.add('center', new Roo.NestedLayoutPanel(inner,
55325 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55329 this.regions.preview = inner.getRegion('south');
55330 this.regions.listView = inner.getRegion('center');
55333 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55335 * Ext JS Library 1.1.1
55336 * Copyright(c) 2006-2007, Ext JS, LLC.
55338 * Originally Released Under LGPL - original licence link has changed is not relivant.
55341 * <script type="text/javascript">
55345 * @class Roo.grid.Grid
55346 * @extends Roo.util.Observable
55347 * This class represents the primary interface of a component based grid control.
55348 * <br><br>Usage:<pre><code>
55349 var grid = new Roo.grid.Grid("my-container-id", {
55352 selModel: mySelectionModel,
55353 autoSizeColumns: true,
55354 monitorWindowResize: false,
55355 trackMouseOver: true
55360 * <b>Common Problems:</b><br/>
55361 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55362 * element will correct this<br/>
55363 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55364 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55365 * are unpredictable.<br/>
55366 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55367 * grid to calculate dimensions/offsets.<br/>
55369 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55370 * The container MUST have some type of size defined for the grid to fill. The container will be
55371 * automatically set to position relative if it isn't already.
55372 * @param {Object} config A config object that sets properties on this grid.
55374 Roo.grid.Grid = function(container, config){
55375 // initialize the container
55376 this.container = Roo.get(container);
55377 this.container.update("");
55378 this.container.setStyle("overflow", "hidden");
55379 this.container.addClass('x-grid-container');
55381 this.id = this.container.id;
55383 Roo.apply(this, config);
55384 // check and correct shorthanded configs
55386 this.dataSource = this.ds;
55390 this.colModel = this.cm;
55394 this.selModel = this.sm;
55398 if (this.selModel) {
55399 this.selModel = Roo.factory(this.selModel, Roo.grid);
55400 this.sm = this.selModel;
55401 this.sm.xmodule = this.xmodule || false;
55403 if (typeof(this.colModel.config) == 'undefined') {
55404 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55405 this.cm = this.colModel;
55406 this.cm.xmodule = this.xmodule || false;
55408 if (this.dataSource) {
55409 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55410 this.ds = this.dataSource;
55411 this.ds.xmodule = this.xmodule || false;
55418 this.container.setWidth(this.width);
55422 this.container.setHeight(this.height);
55429 * The raw click event for the entire grid.
55430 * @param {Roo.EventObject} e
55435 * The raw dblclick event for the entire grid.
55436 * @param {Roo.EventObject} e
55440 * @event contextmenu
55441 * The raw contextmenu event for the entire grid.
55442 * @param {Roo.EventObject} e
55444 "contextmenu" : true,
55447 * The raw mousedown event for the entire grid.
55448 * @param {Roo.EventObject} e
55450 "mousedown" : true,
55453 * The raw mouseup event for the entire grid.
55454 * @param {Roo.EventObject} e
55459 * The raw mouseover event for the entire grid.
55460 * @param {Roo.EventObject} e
55462 "mouseover" : true,
55465 * The raw mouseout event for the entire grid.
55466 * @param {Roo.EventObject} e
55471 * The raw keypress event for the entire grid.
55472 * @param {Roo.EventObject} e
55477 * The raw keydown event for the entire grid.
55478 * @param {Roo.EventObject} e
55486 * Fires when a cell is clicked
55487 * @param {Grid} this
55488 * @param {Number} rowIndex
55489 * @param {Number} columnIndex
55490 * @param {Roo.EventObject} e
55492 "cellclick" : true,
55494 * @event celldblclick
55495 * Fires when a cell is double clicked
55496 * @param {Grid} this
55497 * @param {Number} rowIndex
55498 * @param {Number} columnIndex
55499 * @param {Roo.EventObject} e
55501 "celldblclick" : true,
55504 * Fires when a row is clicked
55505 * @param {Grid} this
55506 * @param {Number} rowIndex
55507 * @param {Roo.EventObject} e
55511 * @event rowdblclick
55512 * Fires when a row is double clicked
55513 * @param {Grid} this
55514 * @param {Number} rowIndex
55515 * @param {Roo.EventObject} e
55517 "rowdblclick" : true,
55519 * @event headerclick
55520 * Fires when a header is clicked
55521 * @param {Grid} this
55522 * @param {Number} columnIndex
55523 * @param {Roo.EventObject} e
55525 "headerclick" : true,
55527 * @event headerdblclick
55528 * Fires when a header cell is double clicked
55529 * @param {Grid} this
55530 * @param {Number} columnIndex
55531 * @param {Roo.EventObject} e
55533 "headerdblclick" : true,
55535 * @event rowcontextmenu
55536 * Fires when a row is right clicked
55537 * @param {Grid} this
55538 * @param {Number} rowIndex
55539 * @param {Roo.EventObject} e
55541 "rowcontextmenu" : true,
55543 * @event cellcontextmenu
55544 * Fires when a cell is right clicked
55545 * @param {Grid} this
55546 * @param {Number} rowIndex
55547 * @param {Number} cellIndex
55548 * @param {Roo.EventObject} e
55550 "cellcontextmenu" : true,
55552 * @event headercontextmenu
55553 * Fires when a header is right clicked
55554 * @param {Grid} this
55555 * @param {Number} columnIndex
55556 * @param {Roo.EventObject} e
55558 "headercontextmenu" : true,
55560 * @event bodyscroll
55561 * Fires when the body element is scrolled
55562 * @param {Number} scrollLeft
55563 * @param {Number} scrollTop
55565 "bodyscroll" : true,
55567 * @event columnresize
55568 * Fires when the user resizes a column
55569 * @param {Number} columnIndex
55570 * @param {Number} newSize
55572 "columnresize" : true,
55574 * @event columnmove
55575 * Fires when the user moves a column
55576 * @param {Number} oldIndex
55577 * @param {Number} newIndex
55579 "columnmove" : true,
55582 * Fires when row(s) start being dragged
55583 * @param {Grid} this
55584 * @param {Roo.GridDD} dd The drag drop object
55585 * @param {event} e The raw browser event
55587 "startdrag" : true,
55590 * Fires when a drag operation is complete
55591 * @param {Grid} this
55592 * @param {Roo.GridDD} dd The drag drop object
55593 * @param {event} e The raw browser event
55598 * Fires when dragged row(s) are dropped on a valid DD target
55599 * @param {Grid} this
55600 * @param {Roo.GridDD} dd The drag drop object
55601 * @param {String} targetId The target drag drop object
55602 * @param {event} e The raw browser event
55607 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55608 * @param {Grid} this
55609 * @param {Roo.GridDD} dd The drag drop object
55610 * @param {String} targetId The target drag drop object
55611 * @param {event} e The raw browser event
55616 * Fires when the dragged row(s) first cross another DD target while being dragged
55617 * @param {Grid} this
55618 * @param {Roo.GridDD} dd The drag drop object
55619 * @param {String} targetId The target drag drop object
55620 * @param {event} e The raw browser event
55622 "dragenter" : true,
55625 * Fires when the dragged row(s) leave another DD target while being dragged
55626 * @param {Grid} this
55627 * @param {Roo.GridDD} dd The drag drop object
55628 * @param {String} targetId The target drag drop object
55629 * @param {event} e The raw browser event
55634 * Fires when a row is rendered, so you can change add a style to it.
55635 * @param {GridView} gridview The grid view
55636 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55642 * Fires when the grid is rendered
55643 * @param {Grid} grid
55648 Roo.grid.Grid.superclass.constructor.call(this);
55650 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55653 * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
55656 * @cfg {Roo.grid.GridView} view The view that renders the grid (default = Roo.grid.GridView)
55659 * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
55662 * @cfg {Roo.grid.Store} ds The data store for the grid
55665 * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
55668 * @cfg {String} ddGroup - drag drop group.
55671 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
55675 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55677 minColumnWidth : 25,
55680 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55681 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55682 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55684 autoSizeColumns : false,
55687 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55689 autoSizeHeaders : true,
55692 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55694 monitorWindowResize : true,
55697 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55698 * rows measured to get a columns size. Default is 0 (all rows).
55700 maxRowsToMeasure : 0,
55703 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55705 trackMouseOver : true,
55708 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55711 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
55715 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55717 enableDragDrop : false,
55720 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55722 enableColumnMove : true,
55725 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55727 enableColumnHide : true,
55730 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55732 enableRowHeightSync : false,
55735 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55740 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55742 autoHeight : false,
55745 * @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.
55747 autoExpandColumn : false,
55750 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55753 autoExpandMin : 50,
55756 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55758 autoExpandMax : 1000,
55761 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55766 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55770 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55780 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55781 * of a fixed width. Default is false.
55784 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55789 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55790 * %0 is replaced with the number of selected rows.
55792 ddText : "{0} selected row{1}",
55796 * Called once after all setup has been completed and the grid is ready to be rendered.
55797 * @return {Roo.grid.Grid} this
55799 render : function()
55801 var c = this.container;
55802 // try to detect autoHeight/width mode
55803 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55804 this.autoHeight = true;
55806 var view = this.getView();
55809 c.on("click", this.onClick, this);
55810 c.on("dblclick", this.onDblClick, this);
55811 c.on("contextmenu", this.onContextMenu, this);
55812 c.on("keydown", this.onKeyDown, this);
55814 c.on("touchstart", this.onTouchStart, this);
55817 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55819 this.getSelectionModel().init(this);
55824 this.loadMask = new Roo.LoadMask(this.container,
55825 Roo.apply({store:this.dataSource}, this.loadMask));
55829 if (this.toolbar && this.toolbar.xtype) {
55830 this.toolbar.container = this.getView().getHeaderPanel(true);
55831 this.toolbar = new Roo.Toolbar(this.toolbar);
55833 if (this.footer && this.footer.xtype) {
55834 this.footer.dataSource = this.getDataSource();
55835 this.footer.container = this.getView().getFooterPanel(true);
55836 this.footer = Roo.factory(this.footer, Roo);
55838 if (this.dropTarget && this.dropTarget.xtype) {
55839 delete this.dropTarget.xtype;
55840 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55844 this.rendered = true;
55845 this.fireEvent('render', this);
55850 * Reconfigures the grid to use a different Store and Column Model.
55851 * The View will be bound to the new objects and refreshed.
55852 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55853 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55855 reconfigure : function(dataSource, colModel){
55857 this.loadMask.destroy();
55858 this.loadMask = new Roo.LoadMask(this.container,
55859 Roo.apply({store:dataSource}, this.loadMask));
55861 this.view.bind(dataSource, colModel);
55862 this.dataSource = dataSource;
55863 this.colModel = colModel;
55864 this.view.refresh(true);
55868 * Add's a column, default at the end..
55870 * @param {int} position to add (default end)
55871 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55873 addColumns : function(pos, ar)
55876 for (var i =0;i< ar.length;i++) {
55878 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55879 this.cm.lookup[cfg.id] = cfg;
55883 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55884 pos = this.cm.config.length; //this.cm.config.push(cfg);
55886 pos = Math.max(0,pos);
55889 this.cm.config.splice.apply(this.cm.config, ar);
55893 this.view.generateRules(this.cm);
55894 this.view.refresh(true);
55902 onKeyDown : function(e){
55903 this.fireEvent("keydown", e);
55907 * Destroy this grid.
55908 * @param {Boolean} removeEl True to remove the element
55910 destroy : function(removeEl, keepListeners){
55912 this.loadMask.destroy();
55914 var c = this.container;
55915 c.removeAllListeners();
55916 this.view.destroy();
55917 this.colModel.purgeListeners();
55918 if(!keepListeners){
55919 this.purgeListeners();
55922 if(removeEl === true){
55928 processEvent : function(name, e){
55929 // does this fire select???
55930 //Roo.log('grid:processEvent ' + name);
55932 if (name != 'touchstart' ) {
55933 this.fireEvent(name, e);
55936 var t = e.getTarget();
55938 var header = v.findHeaderIndex(t);
55939 if(header !== false){
55940 var ename = name == 'touchstart' ? 'click' : name;
55942 this.fireEvent("header" + ename, this, header, e);
55944 var row = v.findRowIndex(t);
55945 var cell = v.findCellIndex(t);
55946 if (name == 'touchstart') {
55947 // first touch is always a click.
55948 // hopefull this happens after selection is updated.?
55951 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55952 var cs = this.selModel.getSelectedCell();
55953 if (row == cs[0] && cell == cs[1]){
55957 if (typeof(this.selModel.getSelections) != 'undefined') {
55958 var cs = this.selModel.getSelections();
55959 var ds = this.dataSource;
55960 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55971 this.fireEvent("row" + name, this, row, e);
55972 if(cell !== false){
55973 this.fireEvent("cell" + name, this, row, cell, e);
55980 onClick : function(e){
55981 this.processEvent("click", e);
55984 onTouchStart : function(e){
55985 this.processEvent("touchstart", e);
55989 onContextMenu : function(e, t){
55990 this.processEvent("contextmenu", e);
55994 onDblClick : function(e){
55995 this.processEvent("dblclick", e);
55999 walkCells : function(row, col, step, fn, scope){
56000 var cm = this.colModel, clen = cm.getColumnCount();
56001 var ds = this.dataSource, rlen = ds.getCount(), first = true;
56013 if(fn.call(scope || this, row, col, cm) === true){
56031 if(fn.call(scope || this, row, col, cm) === true){
56043 getSelections : function(){
56044 return this.selModel.getSelections();
56048 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
56049 * but if manual update is required this method will initiate it.
56051 autoSize : function(){
56053 this.view.layout();
56054 if(this.view.adjustForScroll){
56055 this.view.adjustForScroll();
56061 * Returns the grid's underlying element.
56062 * @return {Element} The element
56064 getGridEl : function(){
56065 return this.container;
56068 // private for compatibility, overridden by editor grid
56069 stopEditing : function(){},
56072 * Returns the grid's SelectionModel.
56073 * @return {SelectionModel}
56075 getSelectionModel : function(){
56076 if(!this.selModel){
56077 this.selModel = new Roo.grid.RowSelectionModel();
56079 return this.selModel;
56083 * Returns the grid's DataSource.
56084 * @return {DataSource}
56086 getDataSource : function(){
56087 return this.dataSource;
56091 * Returns the grid's ColumnModel.
56092 * @return {ColumnModel}
56094 getColumnModel : function(){
56095 return this.colModel;
56099 * Returns the grid's GridView object.
56100 * @return {GridView}
56102 getView : function(){
56104 this.view = new Roo.grid.GridView(this.viewConfig);
56105 this.relayEvents(this.view, [
56106 "beforerowremoved", "beforerowsinserted",
56107 "beforerefresh", "rowremoved",
56108 "rowsinserted", "rowupdated" ,"refresh"
56114 * Called to get grid's drag proxy text, by default returns this.ddText.
56115 * Override this to put something different in the dragged text.
56118 getDragDropText : function(){
56119 var count = this.selModel.getCount();
56120 return String.format(this.ddText, count, count == 1 ? '' : 's');
56125 * Ext JS Library 1.1.1
56126 * Copyright(c) 2006-2007, Ext JS, LLC.
56128 * Originally Released Under LGPL - original licence link has changed is not relivant.
56131 * <script type="text/javascript">
56134 * @class Roo.grid.AbstractGridView
56135 * @extends Roo.util.Observable
56137 * Abstract base class for grid Views
56140 Roo.grid.AbstractGridView = function(){
56144 "beforerowremoved" : true,
56145 "beforerowsinserted" : true,
56146 "beforerefresh" : true,
56147 "rowremoved" : true,
56148 "rowsinserted" : true,
56149 "rowupdated" : true,
56152 Roo.grid.AbstractGridView.superclass.constructor.call(this);
56155 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
56156 rowClass : "x-grid-row",
56157 cellClass : "x-grid-cell",
56158 tdClass : "x-grid-td",
56159 hdClass : "x-grid-hd",
56160 splitClass : "x-grid-hd-split",
56162 init: function(grid){
56164 var cid = this.grid.getGridEl().id;
56165 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
56166 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
56167 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
56168 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
56171 getColumnRenderers : function(){
56172 var renderers = [];
56173 var cm = this.grid.colModel;
56174 var colCount = cm.getColumnCount();
56175 for(var i = 0; i < colCount; i++){
56176 renderers[i] = cm.getRenderer(i);
56181 getColumnIds : function(){
56183 var cm = this.grid.colModel;
56184 var colCount = cm.getColumnCount();
56185 for(var i = 0; i < colCount; i++){
56186 ids[i] = cm.getColumnId(i);
56191 getDataIndexes : function(){
56192 if(!this.indexMap){
56193 this.indexMap = this.buildIndexMap();
56195 return this.indexMap.colToData;
56198 getColumnIndexByDataIndex : function(dataIndex){
56199 if(!this.indexMap){
56200 this.indexMap = this.buildIndexMap();
56202 return this.indexMap.dataToCol[dataIndex];
56206 * Set a css style for a column dynamically.
56207 * @param {Number} colIndex The index of the column
56208 * @param {String} name The css property name
56209 * @param {String} value The css value
56211 setCSSStyle : function(colIndex, name, value){
56212 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
56213 Roo.util.CSS.updateRule(selector, name, value);
56216 generateRules : function(cm){
56217 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
56218 Roo.util.CSS.removeStyleSheet(rulesId);
56219 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56220 var cid = cm.getColumnId(i);
56221 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
56222 this.tdSelector, cid, " {\n}\n",
56223 this.hdSelector, cid, " {\n}\n",
56224 this.splitSelector, cid, " {\n}\n");
56226 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56230 * Ext JS Library 1.1.1
56231 * Copyright(c) 2006-2007, Ext JS, LLC.
56233 * Originally Released Under LGPL - original licence link has changed is not relivant.
56236 * <script type="text/javascript">
56240 // This is a support class used internally by the Grid components
56241 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
56243 this.view = grid.getView();
56244 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56245 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
56247 this.setHandleElId(Roo.id(hd));
56248 this.setOuterHandleElId(Roo.id(hd2));
56250 this.scroll = false;
56252 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
56254 getDragData : function(e){
56255 var t = Roo.lib.Event.getTarget(e);
56256 var h = this.view.findHeaderCell(t);
56258 return {ddel: h.firstChild, header:h};
56263 onInitDrag : function(e){
56264 this.view.headersDisabled = true;
56265 var clone = this.dragData.ddel.cloneNode(true);
56266 clone.id = Roo.id();
56267 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
56268 this.proxy.update(clone);
56272 afterValidDrop : function(){
56274 setTimeout(function(){
56275 v.headersDisabled = false;
56279 afterInvalidDrop : function(){
56281 setTimeout(function(){
56282 v.headersDisabled = false;
56288 * Ext JS Library 1.1.1
56289 * Copyright(c) 2006-2007, Ext JS, LLC.
56291 * Originally Released Under LGPL - original licence link has changed is not relivant.
56294 * <script type="text/javascript">
56297 // This is a support class used internally by the Grid components
56298 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56300 this.view = grid.getView();
56301 // split the proxies so they don't interfere with mouse events
56302 this.proxyTop = Roo.DomHelper.append(document.body, {
56303 cls:"col-move-top", html:" "
56305 this.proxyBottom = Roo.DomHelper.append(document.body, {
56306 cls:"col-move-bottom", html:" "
56308 this.proxyTop.hide = this.proxyBottom.hide = function(){
56309 this.setLeftTop(-100,-100);
56310 this.setStyle("visibility", "hidden");
56312 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56313 // temporarily disabled
56314 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56315 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56317 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56318 proxyOffsets : [-4, -9],
56319 fly: Roo.Element.fly,
56321 getTargetFromEvent : function(e){
56322 var t = Roo.lib.Event.getTarget(e);
56323 var cindex = this.view.findCellIndex(t);
56324 if(cindex !== false){
56325 return this.view.getHeaderCell(cindex);
56330 nextVisible : function(h){
56331 var v = this.view, cm = this.grid.colModel;
56334 if(!cm.isHidden(v.getCellIndex(h))){
56342 prevVisible : function(h){
56343 var v = this.view, cm = this.grid.colModel;
56346 if(!cm.isHidden(v.getCellIndex(h))){
56354 positionIndicator : function(h, n, e){
56355 var x = Roo.lib.Event.getPageX(e);
56356 var r = Roo.lib.Dom.getRegion(n.firstChild);
56357 var px, pt, py = r.top + this.proxyOffsets[1];
56358 if((r.right - x) <= (r.right-r.left)/2){
56359 px = r.right+this.view.borderWidth;
56365 var oldIndex = this.view.getCellIndex(h);
56366 var newIndex = this.view.getCellIndex(n);
56368 if(this.grid.colModel.isFixed(newIndex)){
56372 var locked = this.grid.colModel.isLocked(newIndex);
56377 if(oldIndex < newIndex){
56380 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56383 px += this.proxyOffsets[0];
56384 this.proxyTop.setLeftTop(px, py);
56385 this.proxyTop.show();
56386 if(!this.bottomOffset){
56387 this.bottomOffset = this.view.mainHd.getHeight();
56389 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56390 this.proxyBottom.show();
56394 onNodeEnter : function(n, dd, e, data){
56395 if(data.header != n){
56396 this.positionIndicator(data.header, n, e);
56400 onNodeOver : function(n, dd, e, data){
56401 var result = false;
56402 if(data.header != n){
56403 result = this.positionIndicator(data.header, n, e);
56406 this.proxyTop.hide();
56407 this.proxyBottom.hide();
56409 return result ? this.dropAllowed : this.dropNotAllowed;
56412 onNodeOut : function(n, dd, e, data){
56413 this.proxyTop.hide();
56414 this.proxyBottom.hide();
56417 onNodeDrop : function(n, dd, e, data){
56418 var h = data.header;
56420 var cm = this.grid.colModel;
56421 var x = Roo.lib.Event.getPageX(e);
56422 var r = Roo.lib.Dom.getRegion(n.firstChild);
56423 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56424 var oldIndex = this.view.getCellIndex(h);
56425 var newIndex = this.view.getCellIndex(n);
56426 var locked = cm.isLocked(newIndex);
56430 if(oldIndex < newIndex){
56433 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56436 cm.setLocked(oldIndex, locked, true);
56437 cm.moveColumn(oldIndex, newIndex);
56438 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56446 * Ext JS Library 1.1.1
56447 * Copyright(c) 2006-2007, Ext JS, LLC.
56449 * Originally Released Under LGPL - original licence link has changed is not relivant.
56452 * <script type="text/javascript">
56456 * @class Roo.grid.GridView
56457 * @extends Roo.util.Observable
56460 * @param {Object} config
56462 Roo.grid.GridView = function(config){
56463 Roo.grid.GridView.superclass.constructor.call(this);
56466 Roo.apply(this, config);
56469 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56471 unselectable : 'unselectable="on"',
56472 unselectableCls : 'x-unselectable',
56475 rowClass : "x-grid-row",
56477 cellClass : "x-grid-col",
56479 tdClass : "x-grid-td",
56481 hdClass : "x-grid-hd",
56483 splitClass : "x-grid-split",
56485 sortClasses : ["sort-asc", "sort-desc"],
56487 enableMoveAnim : false,
56491 dh : Roo.DomHelper,
56493 fly : Roo.Element.fly,
56495 css : Roo.util.CSS,
56501 scrollIncrement : 22,
56503 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56505 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56507 bind : function(ds, cm){
56509 this.ds.un("load", this.onLoad, this);
56510 this.ds.un("datachanged", this.onDataChange, this);
56511 this.ds.un("add", this.onAdd, this);
56512 this.ds.un("remove", this.onRemove, this);
56513 this.ds.un("update", this.onUpdate, this);
56514 this.ds.un("clear", this.onClear, this);
56517 ds.on("load", this.onLoad, this);
56518 ds.on("datachanged", this.onDataChange, this);
56519 ds.on("add", this.onAdd, this);
56520 ds.on("remove", this.onRemove, this);
56521 ds.on("update", this.onUpdate, this);
56522 ds.on("clear", this.onClear, this);
56527 this.cm.un("widthchange", this.onColWidthChange, this);
56528 this.cm.un("headerchange", this.onHeaderChange, this);
56529 this.cm.un("hiddenchange", this.onHiddenChange, this);
56530 this.cm.un("columnmoved", this.onColumnMove, this);
56531 this.cm.un("columnlockchange", this.onColumnLock, this);
56534 this.generateRules(cm);
56535 cm.on("widthchange", this.onColWidthChange, this);
56536 cm.on("headerchange", this.onHeaderChange, this);
56537 cm.on("hiddenchange", this.onHiddenChange, this);
56538 cm.on("columnmoved", this.onColumnMove, this);
56539 cm.on("columnlockchange", this.onColumnLock, this);
56544 init: function(grid){
56545 Roo.grid.GridView.superclass.init.call(this, grid);
56547 this.bind(grid.dataSource, grid.colModel);
56549 grid.on("headerclick", this.handleHeaderClick, this);
56551 if(grid.trackMouseOver){
56552 grid.on("mouseover", this.onRowOver, this);
56553 grid.on("mouseout", this.onRowOut, this);
56555 grid.cancelTextSelection = function(){};
56556 this.gridId = grid.id;
56558 var tpls = this.templates || {};
56561 tpls.master = new Roo.Template(
56562 '<div class="x-grid" hidefocus="true">',
56563 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56564 '<div class="x-grid-topbar"></div>',
56565 '<div class="x-grid-scroller"><div></div></div>',
56566 '<div class="x-grid-locked">',
56567 '<div class="x-grid-header">{lockedHeader}</div>',
56568 '<div class="x-grid-body">{lockedBody}</div>',
56570 '<div class="x-grid-viewport">',
56571 '<div class="x-grid-header">{header}</div>',
56572 '<div class="x-grid-body">{body}</div>',
56574 '<div class="x-grid-bottombar"></div>',
56576 '<div class="x-grid-resize-proxy"> </div>',
56579 tpls.master.disableformats = true;
56583 tpls.header = new Roo.Template(
56584 '<table border="0" cellspacing="0" cellpadding="0">',
56585 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56588 tpls.header.disableformats = true;
56590 tpls.header.compile();
56593 tpls.hcell = new Roo.Template(
56594 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56595 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56598 tpls.hcell.disableFormats = true;
56600 tpls.hcell.compile();
56603 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56604 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56605 tpls.hsplit.disableFormats = true;
56607 tpls.hsplit.compile();
56610 tpls.body = new Roo.Template(
56611 '<table border="0" cellspacing="0" cellpadding="0">',
56612 "<tbody>{rows}</tbody>",
56615 tpls.body.disableFormats = true;
56617 tpls.body.compile();
56620 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56621 tpls.row.disableFormats = true;
56623 tpls.row.compile();
56626 tpls.cell = new Roo.Template(
56627 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56628 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56629 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56632 tpls.cell.disableFormats = true;
56634 tpls.cell.compile();
56636 this.templates = tpls;
56639 // remap these for backwards compat
56640 onColWidthChange : function(){
56641 this.updateColumns.apply(this, arguments);
56643 onHeaderChange : function(){
56644 this.updateHeaders.apply(this, arguments);
56646 onHiddenChange : function(){
56647 this.handleHiddenChange.apply(this, arguments);
56649 onColumnMove : function(){
56650 this.handleColumnMove.apply(this, arguments);
56652 onColumnLock : function(){
56653 this.handleLockChange.apply(this, arguments);
56656 onDataChange : function(){
56658 this.updateHeaderSortState();
56661 onClear : function(){
56665 onUpdate : function(ds, record){
56666 this.refreshRow(record);
56669 refreshRow : function(record){
56670 var ds = this.ds, index;
56671 if(typeof record == 'number'){
56673 record = ds.getAt(index);
56675 index = ds.indexOf(record);
56677 this.insertRows(ds, index, index, true);
56678 this.onRemove(ds, record, index+1, true);
56679 this.syncRowHeights(index, index);
56681 this.fireEvent("rowupdated", this, index, record);
56684 onAdd : function(ds, records, index){
56685 this.insertRows(ds, index, index + (records.length-1));
56688 onRemove : function(ds, record, index, isUpdate){
56689 if(isUpdate !== true){
56690 this.fireEvent("beforerowremoved", this, index, record);
56692 var bt = this.getBodyTable(), lt = this.getLockedTable();
56693 if(bt.rows[index]){
56694 bt.firstChild.removeChild(bt.rows[index]);
56696 if(lt.rows[index]){
56697 lt.firstChild.removeChild(lt.rows[index]);
56699 if(isUpdate !== true){
56700 this.stripeRows(index);
56701 this.syncRowHeights(index, index);
56703 this.fireEvent("rowremoved", this, index, record);
56707 onLoad : function(){
56708 this.scrollToTop();
56712 * Scrolls the grid to the top
56714 scrollToTop : function(){
56716 this.scroller.dom.scrollTop = 0;
56722 * Gets a panel in the header of the grid that can be used for toolbars etc.
56723 * After modifying the contents of this panel a call to grid.autoSize() may be
56724 * required to register any changes in size.
56725 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56726 * @return Roo.Element
56728 getHeaderPanel : function(doShow){
56730 this.headerPanel.show();
56732 return this.headerPanel;
56736 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56737 * After modifying the contents of this panel a call to grid.autoSize() may be
56738 * required to register any changes in size.
56739 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56740 * @return Roo.Element
56742 getFooterPanel : function(doShow){
56744 this.footerPanel.show();
56746 return this.footerPanel;
56749 initElements : function(){
56750 var E = Roo.Element;
56751 var el = this.grid.getGridEl().dom.firstChild;
56752 var cs = el.childNodes;
56754 this.el = new E(el);
56756 this.focusEl = new E(el.firstChild);
56757 this.focusEl.swallowEvent("click", true);
56759 this.headerPanel = new E(cs[1]);
56760 this.headerPanel.enableDisplayMode("block");
56762 this.scroller = new E(cs[2]);
56763 this.scrollSizer = new E(this.scroller.dom.firstChild);
56765 this.lockedWrap = new E(cs[3]);
56766 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56767 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56769 this.mainWrap = new E(cs[4]);
56770 this.mainHd = new E(this.mainWrap.dom.firstChild);
56771 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56773 this.footerPanel = new E(cs[5]);
56774 this.footerPanel.enableDisplayMode("block");
56776 this.resizeProxy = new E(cs[6]);
56778 this.headerSelector = String.format(
56779 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56780 this.lockedHd.id, this.mainHd.id
56783 this.splitterSelector = String.format(
56784 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56785 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56788 idToCssName : function(s)
56790 return s.replace(/[^a-z0-9]+/ig, '-');
56793 getHeaderCell : function(index){
56794 return Roo.DomQuery.select(this.headerSelector)[index];
56797 getHeaderCellMeasure : function(index){
56798 return this.getHeaderCell(index).firstChild;
56801 getHeaderCellText : function(index){
56802 return this.getHeaderCell(index).firstChild.firstChild;
56805 getLockedTable : function(){
56806 return this.lockedBody.dom.firstChild;
56809 getBodyTable : function(){
56810 return this.mainBody.dom.firstChild;
56813 getLockedRow : function(index){
56814 return this.getLockedTable().rows[index];
56817 getRow : function(index){
56818 return this.getBodyTable().rows[index];
56821 getRowComposite : function(index){
56823 this.rowEl = new Roo.CompositeElementLite();
56825 var els = [], lrow, mrow;
56826 if(lrow = this.getLockedRow(index)){
56829 if(mrow = this.getRow(index)){
56832 this.rowEl.elements = els;
56836 * Gets the 'td' of the cell
56838 * @param {Integer} rowIndex row to select
56839 * @param {Integer} colIndex column to select
56843 getCell : function(rowIndex, colIndex){
56844 var locked = this.cm.getLockedCount();
56846 if(colIndex < locked){
56847 source = this.lockedBody.dom.firstChild;
56849 source = this.mainBody.dom.firstChild;
56850 colIndex -= locked;
56852 return source.rows[rowIndex].childNodes[colIndex];
56855 getCellText : function(rowIndex, colIndex){
56856 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56859 getCellBox : function(cell){
56860 var b = this.fly(cell).getBox();
56861 if(Roo.isOpera){ // opera fails to report the Y
56862 b.y = cell.offsetTop + this.mainBody.getY();
56867 getCellIndex : function(cell){
56868 var id = String(cell.className).match(this.cellRE);
56870 return parseInt(id[1], 10);
56875 findHeaderIndex : function(n){
56876 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56877 return r ? this.getCellIndex(r) : false;
56880 findHeaderCell : function(n){
56881 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56882 return r ? r : false;
56885 findRowIndex : function(n){
56889 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56890 return r ? r.rowIndex : false;
56893 findCellIndex : function(node){
56894 var stop = this.el.dom;
56895 while(node && node != stop){
56896 if(this.findRE.test(node.className)){
56897 return this.getCellIndex(node);
56899 node = node.parentNode;
56904 getColumnId : function(index){
56905 return this.cm.getColumnId(index);
56908 getSplitters : function()
56910 if(this.splitterSelector){
56911 return Roo.DomQuery.select(this.splitterSelector);
56917 getSplitter : function(index){
56918 return this.getSplitters()[index];
56921 onRowOver : function(e, t){
56923 if((row = this.findRowIndex(t)) !== false){
56924 this.getRowComposite(row).addClass("x-grid-row-over");
56928 onRowOut : function(e, t){
56930 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56931 this.getRowComposite(row).removeClass("x-grid-row-over");
56935 renderHeaders : function(){
56937 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56938 var cb = [], lb = [], sb = [], lsb = [], p = {};
56939 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56940 p.cellId = "x-grid-hd-0-" + i;
56941 p.splitId = "x-grid-csplit-0-" + i;
56942 p.id = cm.getColumnId(i);
56943 p.value = cm.getColumnHeader(i) || "";
56944 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56945 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56946 if(!cm.isLocked(i)){
56947 cb[cb.length] = ct.apply(p);
56948 sb[sb.length] = st.apply(p);
56950 lb[lb.length] = ct.apply(p);
56951 lsb[lsb.length] = st.apply(p);
56954 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56955 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56958 updateHeaders : function(){
56959 var html = this.renderHeaders();
56960 this.lockedHd.update(html[0]);
56961 this.mainHd.update(html[1]);
56965 * Focuses the specified row.
56966 * @param {Number} row The row index
56968 focusRow : function(row)
56970 //Roo.log('GridView.focusRow');
56971 var x = this.scroller.dom.scrollLeft;
56972 this.focusCell(row, 0, false);
56973 this.scroller.dom.scrollLeft = x;
56977 * Focuses the specified cell.
56978 * @param {Number} row The row index
56979 * @param {Number} col The column index
56980 * @param {Boolean} hscroll false to disable horizontal scrolling
56982 focusCell : function(row, col, hscroll)
56984 //Roo.log('GridView.focusCell');
56985 var el = this.ensureVisible(row, col, hscroll);
56986 this.focusEl.alignTo(el, "tl-tl");
56988 this.focusEl.focus();
56990 this.focusEl.focus.defer(1, this.focusEl);
56995 * Scrolls the specified cell into view
56996 * @param {Number} row The row index
56997 * @param {Number} col The column index
56998 * @param {Boolean} hscroll false to disable horizontal scrolling
57000 ensureVisible : function(row, col, hscroll)
57002 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
57003 //return null; //disable for testing.
57004 if(typeof row != "number"){
57005 row = row.rowIndex;
57007 if(row < 0 && row >= this.ds.getCount()){
57010 col = (col !== undefined ? col : 0);
57011 var cm = this.grid.colModel;
57012 while(cm.isHidden(col)){
57016 var el = this.getCell(row, col);
57020 var c = this.scroller.dom;
57022 var ctop = parseInt(el.offsetTop, 10);
57023 var cleft = parseInt(el.offsetLeft, 10);
57024 var cbot = ctop + el.offsetHeight;
57025 var cright = cleft + el.offsetWidth;
57027 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
57028 var stop = parseInt(c.scrollTop, 10);
57029 var sleft = parseInt(c.scrollLeft, 10);
57030 var sbot = stop + ch;
57031 var sright = sleft + c.clientWidth;
57033 Roo.log('GridView.ensureVisible:' +
57035 ' c.clientHeight:' + c.clientHeight +
57036 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
57044 c.scrollTop = ctop;
57045 //Roo.log("set scrolltop to ctop DISABLE?");
57046 }else if(cbot > sbot){
57047 //Roo.log("set scrolltop to cbot-ch");
57048 c.scrollTop = cbot-ch;
57051 if(hscroll !== false){
57053 c.scrollLeft = cleft;
57054 }else if(cright > sright){
57055 c.scrollLeft = cright-c.clientWidth;
57062 updateColumns : function(){
57063 this.grid.stopEditing();
57064 var cm = this.grid.colModel, colIds = this.getColumnIds();
57065 //var totalWidth = cm.getTotalWidth();
57067 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57068 //if(cm.isHidden(i)) continue;
57069 var w = cm.getColumnWidth(i);
57070 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
57071 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
57073 this.updateSplitters();
57076 generateRules : function(cm){
57077 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
57078 Roo.util.CSS.removeStyleSheet(rulesId);
57079 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57080 var cid = cm.getColumnId(i);
57082 if(cm.config[i].align){
57083 align = 'text-align:'+cm.config[i].align+';';
57086 if(cm.isHidden(i)){
57087 hidden = 'display:none;';
57089 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
57091 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
57092 this.hdSelector, cid, " {\n", align, width, "}\n",
57093 this.tdSelector, cid, " {\n",hidden,"\n}\n",
57094 this.splitSelector, cid, " {\n", hidden , "\n}\n");
57096 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
57099 updateSplitters : function(){
57100 var cm = this.cm, s = this.getSplitters();
57101 if(s){ // splitters not created yet
57102 var pos = 0, locked = true;
57103 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57104 if(cm.isHidden(i)) {
57107 var w = cm.getColumnWidth(i); // make sure it's a number
57108 if(!cm.isLocked(i) && locked){
57113 s[i].style.left = (pos-this.splitOffset) + "px";
57118 handleHiddenChange : function(colModel, colIndex, hidden){
57120 this.hideColumn(colIndex);
57122 this.unhideColumn(colIndex);
57126 hideColumn : function(colIndex){
57127 var cid = this.getColumnId(colIndex);
57128 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
57129 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
57131 this.updateHeaders();
57133 this.updateSplitters();
57137 unhideColumn : function(colIndex){
57138 var cid = this.getColumnId(colIndex);
57139 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
57140 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
57143 this.updateHeaders();
57145 this.updateSplitters();
57149 insertRows : function(dm, firstRow, lastRow, isUpdate){
57150 if(firstRow == 0 && lastRow == dm.getCount()-1){
57154 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
57156 var s = this.getScrollState();
57157 var markup = this.renderRows(firstRow, lastRow);
57158 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
57159 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
57160 this.restoreScroll(s);
57162 this.fireEvent("rowsinserted", this, firstRow, lastRow);
57163 this.syncRowHeights(firstRow, lastRow);
57164 this.stripeRows(firstRow);
57170 bufferRows : function(markup, target, index){
57171 var before = null, trows = target.rows, tbody = target.tBodies[0];
57172 if(index < trows.length){
57173 before = trows[index];
57175 var b = document.createElement("div");
57176 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
57177 var rows = b.firstChild.rows;
57178 for(var i = 0, len = rows.length; i < len; i++){
57180 tbody.insertBefore(rows[0], before);
57182 tbody.appendChild(rows[0]);
57189 deleteRows : function(dm, firstRow, lastRow){
57190 if(dm.getRowCount()<1){
57191 this.fireEvent("beforerefresh", this);
57192 this.mainBody.update("");
57193 this.lockedBody.update("");
57194 this.fireEvent("refresh", this);
57196 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
57197 var bt = this.getBodyTable();
57198 var tbody = bt.firstChild;
57199 var rows = bt.rows;
57200 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
57201 tbody.removeChild(rows[firstRow]);
57203 this.stripeRows(firstRow);
57204 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
57208 updateRows : function(dataSource, firstRow, lastRow){
57209 var s = this.getScrollState();
57211 this.restoreScroll(s);
57214 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
57218 this.updateHeaderSortState();
57221 getScrollState : function(){
57223 var sb = this.scroller.dom;
57224 return {left: sb.scrollLeft, top: sb.scrollTop};
57227 stripeRows : function(startRow){
57228 if(!this.grid.stripeRows || this.ds.getCount() < 1){
57231 startRow = startRow || 0;
57232 var rows = this.getBodyTable().rows;
57233 var lrows = this.getLockedTable().rows;
57234 var cls = ' x-grid-row-alt ';
57235 for(var i = startRow, len = rows.length; i < len; i++){
57236 var row = rows[i], lrow = lrows[i];
57237 var isAlt = ((i+1) % 2 == 0);
57238 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
57239 if(isAlt == hasAlt){
57243 row.className += " x-grid-row-alt";
57245 row.className = row.className.replace("x-grid-row-alt", "");
57248 lrow.className = row.className;
57253 restoreScroll : function(state){
57254 //Roo.log('GridView.restoreScroll');
57255 var sb = this.scroller.dom;
57256 sb.scrollLeft = state.left;
57257 sb.scrollTop = state.top;
57261 syncScroll : function(){
57262 //Roo.log('GridView.syncScroll');
57263 var sb = this.scroller.dom;
57264 var sh = this.mainHd.dom;
57265 var bs = this.mainBody.dom;
57266 var lv = this.lockedBody.dom;
57267 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
57268 lv.scrollTop = bs.scrollTop = sb.scrollTop;
57271 handleScroll : function(e){
57273 var sb = this.scroller.dom;
57274 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
57278 handleWheel : function(e){
57279 var d = e.getWheelDelta();
57280 this.scroller.dom.scrollTop -= d*22;
57281 // set this here to prevent jumpy scrolling on large tables
57282 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
57286 renderRows : function(startRow, endRow){
57287 // pull in all the crap needed to render rows
57288 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
57289 var colCount = cm.getColumnCount();
57291 if(ds.getCount() < 1){
57295 // build a map for all the columns
57297 for(var i = 0; i < colCount; i++){
57298 var name = cm.getDataIndex(i);
57300 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57301 renderer : cm.getRenderer(i),
57302 id : cm.getColumnId(i),
57303 locked : cm.isLocked(i),
57304 has_editor : cm.isCellEditable(i)
57308 startRow = startRow || 0;
57309 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57311 // records to render
57312 var rs = ds.getRange(startRow, endRow);
57314 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57317 // As much as I hate to duplicate code, this was branched because FireFox really hates
57318 // [].join("") on strings. The performance difference was substantial enough to
57319 // branch this function
57320 doRender : Roo.isGecko ?
57321 function(cs, rs, ds, startRow, colCount, stripe){
57322 var ts = this.templates, ct = ts.cell, rt = ts.row;
57324 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57326 var hasListener = this.grid.hasListener('rowclass');
57328 for(var j = 0, len = rs.length; j < len; j++){
57329 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57330 for(var i = 0; i < colCount; i++){
57332 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57334 p.css = p.attr = "";
57335 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57336 if(p.value == undefined || p.value === "") {
57337 p.value = " ";
57340 p.css += ' x-grid-editable-cell';
57342 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57343 p.css += ' x-grid-dirty-cell';
57345 var markup = ct.apply(p);
57353 if(stripe && ((rowIndex+1) % 2 == 0)){
57354 alt.push("x-grid-row-alt")
57357 alt.push( " x-grid-dirty-row");
57360 if(this.getRowClass){
57361 alt.push(this.getRowClass(r, rowIndex));
57367 rowIndex : rowIndex,
57370 this.grid.fireEvent('rowclass', this, rowcfg);
57371 alt.push(rowcfg.rowClass);
57373 rp.alt = alt.join(" ");
57374 lbuf+= rt.apply(rp);
57376 buf+= rt.apply(rp);
57378 return [lbuf, buf];
57380 function(cs, rs, ds, startRow, colCount, stripe){
57381 var ts = this.templates, ct = ts.cell, rt = ts.row;
57383 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57384 var hasListener = this.grid.hasListener('rowclass');
57387 for(var j = 0, len = rs.length; j < len; j++){
57388 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57389 for(var i = 0; i < colCount; i++){
57391 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57393 p.css = p.attr = "";
57394 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57395 if(p.value == undefined || p.value === "") {
57396 p.value = " ";
57400 p.css += ' x-grid-editable-cell';
57402 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57403 p.css += ' x-grid-dirty-cell'
57406 var markup = ct.apply(p);
57408 cb[cb.length] = markup;
57410 lcb[lcb.length] = markup;
57414 if(stripe && ((rowIndex+1) % 2 == 0)){
57415 alt.push( "x-grid-row-alt");
57418 alt.push(" x-grid-dirty-row");
57421 if(this.getRowClass){
57422 alt.push( this.getRowClass(r, rowIndex));
57428 rowIndex : rowIndex,
57431 this.grid.fireEvent('rowclass', this, rowcfg);
57432 alt.push(rowcfg.rowClass);
57435 rp.alt = alt.join(" ");
57436 rp.cells = lcb.join("");
57437 lbuf[lbuf.length] = rt.apply(rp);
57438 rp.cells = cb.join("");
57439 buf[buf.length] = rt.apply(rp);
57441 return [lbuf.join(""), buf.join("")];
57444 renderBody : function(){
57445 var markup = this.renderRows();
57446 var bt = this.templates.body;
57447 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57451 * Refreshes the grid
57452 * @param {Boolean} headersToo
57454 refresh : function(headersToo){
57455 this.fireEvent("beforerefresh", this);
57456 this.grid.stopEditing();
57457 var result = this.renderBody();
57458 this.lockedBody.update(result[0]);
57459 this.mainBody.update(result[1]);
57460 if(headersToo === true){
57461 this.updateHeaders();
57462 this.updateColumns();
57463 this.updateSplitters();
57464 this.updateHeaderSortState();
57466 this.syncRowHeights();
57468 this.fireEvent("refresh", this);
57471 handleColumnMove : function(cm, oldIndex, newIndex){
57472 this.indexMap = null;
57473 var s = this.getScrollState();
57474 this.refresh(true);
57475 this.restoreScroll(s);
57476 this.afterMove(newIndex);
57479 afterMove : function(colIndex){
57480 if(this.enableMoveAnim && Roo.enableFx){
57481 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57483 // if multisort - fix sortOrder, and reload..
57484 if (this.grid.dataSource.multiSort) {
57485 // the we can call sort again..
57486 var dm = this.grid.dataSource;
57487 var cm = this.grid.colModel;
57489 for(var i = 0; i < cm.config.length; i++ ) {
57491 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57492 continue; // dont' bother, it's not in sort list or being set.
57495 so.push(cm.config[i].dataIndex);
57498 dm.load(dm.lastOptions);
57505 updateCell : function(dm, rowIndex, dataIndex){
57506 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57507 if(typeof colIndex == "undefined"){ // not present in grid
57510 var cm = this.grid.colModel;
57511 var cell = this.getCell(rowIndex, colIndex);
57512 var cellText = this.getCellText(rowIndex, colIndex);
57515 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57516 id : cm.getColumnId(colIndex),
57517 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57519 var renderer = cm.getRenderer(colIndex);
57520 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57521 if(typeof val == "undefined" || val === "") {
57524 cellText.innerHTML = val;
57525 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57526 this.syncRowHeights(rowIndex, rowIndex);
57529 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57531 if(this.grid.autoSizeHeaders){
57532 var h = this.getHeaderCellMeasure(colIndex);
57533 maxWidth = Math.max(maxWidth, h.scrollWidth);
57536 if(this.cm.isLocked(colIndex)){
57537 tb = this.getLockedTable();
57540 tb = this.getBodyTable();
57541 index = colIndex - this.cm.getLockedCount();
57544 var rows = tb.rows;
57545 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57546 for(var i = 0; i < stopIndex; i++){
57547 var cell = rows[i].childNodes[index].firstChild;
57548 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57551 return maxWidth + /*margin for error in IE*/ 5;
57554 * Autofit a column to its content.
57555 * @param {Number} colIndex
57556 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57558 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57559 if(this.cm.isHidden(colIndex)){
57560 return; // can't calc a hidden column
57563 var cid = this.cm.getColumnId(colIndex);
57564 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57565 if(this.grid.autoSizeHeaders){
57566 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57569 var newWidth = this.calcColumnWidth(colIndex);
57570 this.cm.setColumnWidth(colIndex,
57571 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57572 if(!suppressEvent){
57573 this.grid.fireEvent("columnresize", colIndex, newWidth);
57578 * Autofits all columns to their content and then expands to fit any extra space in the grid
57580 autoSizeColumns : function(){
57581 var cm = this.grid.colModel;
57582 var colCount = cm.getColumnCount();
57583 for(var i = 0; i < colCount; i++){
57584 this.autoSizeColumn(i, true, true);
57586 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57589 this.updateColumns();
57595 * Autofits all columns to the grid's width proportionate with their current size
57596 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57598 fitColumns : function(reserveScrollSpace){
57599 var cm = this.grid.colModel;
57600 var colCount = cm.getColumnCount();
57604 for (i = 0; i < colCount; i++){
57605 if(!cm.isHidden(i) && !cm.isFixed(i)){
57606 w = cm.getColumnWidth(i);
57612 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57613 if(reserveScrollSpace){
57616 var frac = (avail - cm.getTotalWidth())/width;
57617 while (cols.length){
57620 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57622 this.updateColumns();
57626 onRowSelect : function(rowIndex){
57627 var row = this.getRowComposite(rowIndex);
57628 row.addClass("x-grid-row-selected");
57631 onRowDeselect : function(rowIndex){
57632 var row = this.getRowComposite(rowIndex);
57633 row.removeClass("x-grid-row-selected");
57636 onCellSelect : function(row, col){
57637 var cell = this.getCell(row, col);
57639 Roo.fly(cell).addClass("x-grid-cell-selected");
57643 onCellDeselect : function(row, col){
57644 var cell = this.getCell(row, col);
57646 Roo.fly(cell).removeClass("x-grid-cell-selected");
57650 updateHeaderSortState : function(){
57652 // sort state can be single { field: xxx, direction : yyy}
57653 // or { xxx=>ASC , yyy : DESC ..... }
57656 if (!this.ds.multiSort) {
57657 var state = this.ds.getSortState();
57661 mstate[state.field] = state.direction;
57662 // FIXME... - this is not used here.. but might be elsewhere..
57663 this.sortState = state;
57666 mstate = this.ds.sortToggle;
57668 //remove existing sort classes..
57670 var sc = this.sortClasses;
57671 var hds = this.el.select(this.headerSelector).removeClass(sc);
57673 for(var f in mstate) {
57675 var sortColumn = this.cm.findColumnIndex(f);
57677 if(sortColumn != -1){
57678 var sortDir = mstate[f];
57679 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57688 handleHeaderClick : function(g, index,e){
57690 Roo.log("header click");
57693 // touch events on header are handled by context
57694 this.handleHdCtx(g,index,e);
57699 if(this.headersDisabled){
57702 var dm = g.dataSource, cm = g.colModel;
57703 if(!cm.isSortable(index)){
57708 if (dm.multiSort) {
57709 // update the sortOrder
57711 for(var i = 0; i < cm.config.length; i++ ) {
57713 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57714 continue; // dont' bother, it's not in sort list or being set.
57717 so.push(cm.config[i].dataIndex);
57723 dm.sort(cm.getDataIndex(index));
57727 destroy : function(){
57729 this.colMenu.removeAll();
57730 Roo.menu.MenuMgr.unregister(this.colMenu);
57731 this.colMenu.getEl().remove();
57732 delete this.colMenu;
57735 this.hmenu.removeAll();
57736 Roo.menu.MenuMgr.unregister(this.hmenu);
57737 this.hmenu.getEl().remove();
57740 if(this.grid.enableColumnMove){
57741 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57743 for(var dd in dds){
57744 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57745 var elid = dds[dd].dragElId;
57747 Roo.get(elid).remove();
57748 } else if(dds[dd].config.isTarget){
57749 dds[dd].proxyTop.remove();
57750 dds[dd].proxyBottom.remove();
57753 if(Roo.dd.DDM.locationCache[dd]){
57754 delete Roo.dd.DDM.locationCache[dd];
57757 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57760 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57761 this.bind(null, null);
57762 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57765 handleLockChange : function(){
57766 this.refresh(true);
57769 onDenyColumnLock : function(){
57773 onDenyColumnHide : function(){
57777 handleHdMenuClick : function(item){
57778 var index = this.hdCtxIndex;
57779 var cm = this.cm, ds = this.ds;
57782 ds.sort(cm.getDataIndex(index), "ASC");
57785 ds.sort(cm.getDataIndex(index), "DESC");
57788 var lc = cm.getLockedCount();
57789 if(cm.getColumnCount(true) <= lc+1){
57790 this.onDenyColumnLock();
57794 cm.setLocked(index, true, true);
57795 cm.moveColumn(index, lc);
57796 this.grid.fireEvent("columnmove", index, lc);
57798 cm.setLocked(index, true);
57802 var lc = cm.getLockedCount();
57803 if((lc-1) != index){
57804 cm.setLocked(index, false, true);
57805 cm.moveColumn(index, lc-1);
57806 this.grid.fireEvent("columnmove", index, lc-1);
57808 cm.setLocked(index, false);
57811 case 'wider': // used to expand cols on touch..
57813 var cw = cm.getColumnWidth(index);
57814 cw += (item.id == 'wider' ? 1 : -1) * 50;
57815 cw = Math.max(0, cw);
57816 cw = Math.min(cw,4000);
57817 cm.setColumnWidth(index, cw);
57821 index = cm.getIndexById(item.id.substr(4));
57823 if(item.checked && cm.getColumnCount(true) <= 1){
57824 this.onDenyColumnHide();
57827 cm.setHidden(index, item.checked);
57833 beforeColMenuShow : function(){
57834 var cm = this.cm, colCount = cm.getColumnCount();
57835 this.colMenu.removeAll();
57836 for(var i = 0; i < colCount; i++){
57837 this.colMenu.add(new Roo.menu.CheckItem({
57838 id: "col-"+cm.getColumnId(i),
57839 text: cm.getColumnHeader(i),
57840 checked: !cm.isHidden(i),
57846 handleHdCtx : function(g, index, e){
57848 var hd = this.getHeaderCell(index);
57849 this.hdCtxIndex = index;
57850 var ms = this.hmenu.items, cm = this.cm;
57851 ms.get("asc").setDisabled(!cm.isSortable(index));
57852 ms.get("desc").setDisabled(!cm.isSortable(index));
57853 if(this.grid.enableColLock !== false){
57854 ms.get("lock").setDisabled(cm.isLocked(index));
57855 ms.get("unlock").setDisabled(!cm.isLocked(index));
57857 this.hmenu.show(hd, "tl-bl");
57860 handleHdOver : function(e){
57861 var hd = this.findHeaderCell(e.getTarget());
57862 if(hd && !this.headersDisabled){
57863 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57864 this.fly(hd).addClass("x-grid-hd-over");
57869 handleHdOut : function(e){
57870 var hd = this.findHeaderCell(e.getTarget());
57872 this.fly(hd).removeClass("x-grid-hd-over");
57876 handleSplitDblClick : function(e, t){
57877 var i = this.getCellIndex(t);
57878 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57879 this.autoSizeColumn(i, true);
57884 render : function(){
57887 var colCount = cm.getColumnCount();
57889 if(this.grid.monitorWindowResize === true){
57890 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57892 var header = this.renderHeaders();
57893 var body = this.templates.body.apply({rows:""});
57894 var html = this.templates.master.apply({
57897 lockedHeader: header[0],
57901 //this.updateColumns();
57903 this.grid.getGridEl().dom.innerHTML = html;
57905 this.initElements();
57907 // a kludge to fix the random scolling effect in webkit
57908 this.el.on("scroll", function() {
57909 this.el.dom.scrollTop=0; // hopefully not recursive..
57912 this.scroller.on("scroll", this.handleScroll, this);
57913 this.lockedBody.on("mousewheel", this.handleWheel, this);
57914 this.mainBody.on("mousewheel", this.handleWheel, this);
57916 this.mainHd.on("mouseover", this.handleHdOver, this);
57917 this.mainHd.on("mouseout", this.handleHdOut, this);
57918 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57919 {delegate: "."+this.splitClass});
57921 this.lockedHd.on("mouseover", this.handleHdOver, this);
57922 this.lockedHd.on("mouseout", this.handleHdOut, this);
57923 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57924 {delegate: "."+this.splitClass});
57926 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57927 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57930 this.updateSplitters();
57932 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57933 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57934 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57937 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57938 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57940 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57941 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57943 if(this.grid.enableColLock !== false){
57944 this.hmenu.add('-',
57945 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57946 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57950 this.hmenu.add('-',
57951 {id:"wider", text: this.columnsWiderText},
57952 {id:"narrow", text: this.columnsNarrowText }
57958 if(this.grid.enableColumnHide !== false){
57960 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57961 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57962 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57964 this.hmenu.add('-',
57965 {id:"columns", text: this.columnsText, menu: this.colMenu}
57968 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57970 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57973 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57974 this.dd = new Roo.grid.GridDragZone(this.grid, {
57975 ddGroup : this.grid.ddGroup || 'GridDD'
57981 for(var i = 0; i < colCount; i++){
57982 if(cm.isHidden(i)){
57983 this.hideColumn(i);
57985 if(cm.config[i].align){
57986 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57987 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57991 this.updateHeaderSortState();
57993 this.beforeInitialResize();
57996 // two part rendering gives faster view to the user
57997 this.renderPhase2.defer(1, this);
58000 renderPhase2 : function(){
58001 // render the rows now
58003 if(this.grid.autoSizeColumns){
58004 this.autoSizeColumns();
58008 beforeInitialResize : function(){
58012 onColumnSplitterMoved : function(i, w){
58013 this.userResized = true;
58014 var cm = this.grid.colModel;
58015 cm.setColumnWidth(i, w, true);
58016 var cid = cm.getColumnId(i);
58017 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
58018 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
58019 this.updateSplitters();
58021 this.grid.fireEvent("columnresize", i, w);
58024 syncRowHeights : function(startIndex, endIndex){
58025 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
58026 startIndex = startIndex || 0;
58027 var mrows = this.getBodyTable().rows;
58028 var lrows = this.getLockedTable().rows;
58029 var len = mrows.length-1;
58030 endIndex = Math.min(endIndex || len, len);
58031 for(var i = startIndex; i <= endIndex; i++){
58032 var m = mrows[i], l = lrows[i];
58033 var h = Math.max(m.offsetHeight, l.offsetHeight);
58034 m.style.height = l.style.height = h + "px";
58039 layout : function(initialRender, is2ndPass)
58042 var auto = g.autoHeight;
58043 var scrollOffset = 16;
58044 var c = g.getGridEl(), cm = this.cm,
58045 expandCol = g.autoExpandColumn,
58047 //c.beginMeasure();
58049 if(!c.dom.offsetWidth){ // display:none?
58051 this.lockedWrap.show();
58052 this.mainWrap.show();
58057 var hasLock = this.cm.isLocked(0);
58059 var tbh = this.headerPanel.getHeight();
58060 var bbh = this.footerPanel.getHeight();
58063 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
58064 var newHeight = ch + c.getBorderWidth("tb");
58066 newHeight = Math.min(g.maxHeight, newHeight);
58068 c.setHeight(newHeight);
58072 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
58075 var s = this.scroller;
58077 var csize = c.getSize(true);
58079 this.el.setSize(csize.width, csize.height);
58081 this.headerPanel.setWidth(csize.width);
58082 this.footerPanel.setWidth(csize.width);
58084 var hdHeight = this.mainHd.getHeight();
58085 var vw = csize.width;
58086 var vh = csize.height - (tbh + bbh);
58090 var bt = this.getBodyTable();
58092 if(cm.getLockedCount() == cm.config.length){
58093 bt = this.getLockedTable();
58096 var ltWidth = hasLock ?
58097 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
58099 var scrollHeight = bt.offsetHeight;
58100 var scrollWidth = ltWidth + bt.offsetWidth;
58101 var vscroll = false, hscroll = false;
58103 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
58105 var lw = this.lockedWrap, mw = this.mainWrap;
58106 var lb = this.lockedBody, mb = this.mainBody;
58108 setTimeout(function(){
58109 var t = s.dom.offsetTop;
58110 var w = s.dom.clientWidth,
58111 h = s.dom.clientHeight;
58114 lw.setSize(ltWidth, h);
58116 mw.setLeftTop(ltWidth, t);
58117 mw.setSize(w-ltWidth, h);
58119 lb.setHeight(h-hdHeight);
58120 mb.setHeight(h-hdHeight);
58122 if(is2ndPass !== true && !gv.userResized && expandCol){
58123 // high speed resize without full column calculation
58125 var ci = cm.getIndexById(expandCol);
58127 ci = cm.findColumnIndex(expandCol);
58129 ci = Math.max(0, ci); // make sure it's got at least the first col.
58130 var expandId = cm.getColumnId(ci);
58131 var tw = cm.getTotalWidth(false);
58132 var currentWidth = cm.getColumnWidth(ci);
58133 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
58134 if(currentWidth != cw){
58135 cm.setColumnWidth(ci, cw, true);
58136 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
58137 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
58138 gv.updateSplitters();
58139 gv.layout(false, true);
58151 onWindowResize : function(){
58152 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
58158 appendFooter : function(parentEl){
58162 sortAscText : "Sort Ascending",
58163 sortDescText : "Sort Descending",
58164 lockText : "Lock Column",
58165 unlockText : "Unlock Column",
58166 columnsText : "Columns",
58168 columnsWiderText : "Wider",
58169 columnsNarrowText : "Thinner"
58173 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
58174 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
58175 this.proxy.el.addClass('x-grid3-col-dd');
58178 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
58179 handleMouseDown : function(e){
58183 callHandleMouseDown : function(e){
58184 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
58189 * Ext JS Library 1.1.1
58190 * Copyright(c) 2006-2007, Ext JS, LLC.
58192 * Originally Released Under LGPL - original licence link has changed is not relivant.
58195 * <script type="text/javascript">
58198 * @extends Roo.dd.DDProxy
58199 * @class Roo.grid.SplitDragZone
58200 * Support for Column Header resizing
58202 * @param {Object} config
58205 // This is a support class used internally by the Grid components
58206 Roo.grid.SplitDragZone = function(grid, hd, hd2){
58208 this.view = grid.getView();
58209 this.proxy = this.view.resizeProxy;
58210 Roo.grid.SplitDragZone.superclass.constructor.call(
58213 "gridSplitters" + this.grid.getGridEl().id, // SGROUP
58215 dragElId : Roo.id(this.proxy.dom),
58220 this.setHandleElId(Roo.id(hd));
58221 if (hd2 !== false) {
58222 this.setOuterHandleElId(Roo.id(hd2));
58225 this.scroll = false;
58227 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
58228 fly: Roo.Element.fly,
58230 b4StartDrag : function(x, y){
58231 this.view.headersDisabled = true;
58232 var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
58233 this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
58235 this.proxy.setHeight(h);
58237 // for old system colWidth really stored the actual width?
58238 // in bootstrap we tried using xs/ms/etc.. to do % sizing?
58239 // which in reality did not work.. - it worked only for fixed sizes
58240 // for resizable we need to use actual sizes.
58241 var w = this.cm.getColumnWidth(this.cellIndex);
58242 if (!this.view.mainWrap) {
58244 w = this.view.getHeaderIndex(this.cellIndex).getWidth();
58249 // this was w-this.grid.minColumnWidth;
58250 // doesnt really make sense? - w = thie curren width or the rendered one?
58251 var minw = Math.max(w-this.grid.minColumnWidth, 0);
58252 this.resetConstraints();
58253 this.setXConstraint(minw, 1000);
58254 this.setYConstraint(0, 0);
58255 this.minX = x - minw;
58256 this.maxX = x + 1000;
58258 if (!this.view.mainWrap) { // this is Bootstrap code..
58259 this.getDragEl().style.display='block';
58262 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
58266 handleMouseDown : function(e){
58267 ev = Roo.EventObject.setEvent(e);
58268 var t = this.fly(ev.getTarget());
58269 if(t.hasClass("x-grid-split")){
58270 this.cellIndex = this.view.getCellIndex(t.dom);
58271 this.split = t.dom;
58272 this.cm = this.grid.colModel;
58273 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
58274 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
58279 endDrag : function(e){
58280 this.view.headersDisabled = false;
58281 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
58282 var diff = endX - this.startPos;
58284 var w = this.cm.getColumnWidth(this.cellIndex);
58285 if (!this.view.mainWrap) {
58288 this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
58291 autoOffset : function(){
58292 this.setDelta(0,0);
58296 * Ext JS Library 1.1.1
58297 * Copyright(c) 2006-2007, Ext JS, LLC.
58299 * Originally Released Under LGPL - original licence link has changed is not relivant.
58302 * <script type="text/javascript">
58306 // This is a support class used internally by the Grid components
58307 Roo.grid.GridDragZone = function(grid, config){
58308 this.view = grid.getView();
58309 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
58310 if(this.view.lockedBody){
58311 this.setHandleElId(Roo.id(this.view.mainBody.dom));
58312 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
58314 this.scroll = false;
58316 this.ddel = document.createElement('div');
58317 this.ddel.className = 'x-grid-dd-wrap';
58320 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
58321 ddGroup : "GridDD",
58323 getDragData : function(e){
58324 var t = Roo.lib.Event.getTarget(e);
58325 var rowIndex = this.view.findRowIndex(t);
58326 var sm = this.grid.selModel;
58328 //Roo.log(rowIndex);
58330 if (sm.getSelectedCell) {
58331 // cell selection..
58332 if (!sm.getSelectedCell()) {
58335 if (rowIndex != sm.getSelectedCell()[0]) {
58340 if (sm.getSelections && sm.getSelections().length < 1) {
58345 // before it used to all dragging of unseleted... - now we dont do that.
58346 if(rowIndex !== false){
58351 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58353 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58356 if (e.hasModifier()){
58357 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58360 Roo.log("getDragData");
58365 rowIndex: rowIndex,
58366 selections: sm.getSelections ? sm.getSelections() : (
58367 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
58374 onInitDrag : function(e){
58375 var data = this.dragData;
58376 this.ddel.innerHTML = this.grid.getDragDropText();
58377 this.proxy.update(this.ddel);
58378 // fire start drag?
58381 afterRepair : function(){
58382 this.dragging = false;
58385 getRepairXY : function(e, data){
58389 onEndDrag : function(data, e){
58393 onValidDrop : function(dd, e, id){
58398 beforeInvalidDrop : function(e, id){
58403 * Ext JS Library 1.1.1
58404 * Copyright(c) 2006-2007, Ext JS, LLC.
58406 * Originally Released Under LGPL - original licence link has changed is not relivant.
58409 * <script type="text/javascript">
58414 * @class Roo.grid.ColumnModel
58415 * @extends Roo.util.Observable
58416 * This is the default implementation of a ColumnModel used by the Grid. It defines
58417 * the columns in the grid.
58420 var colModel = new Roo.grid.ColumnModel([
58421 {header: "Ticker", width: 60, sortable: true, locked: true},
58422 {header: "Company Name", width: 150, sortable: true},
58423 {header: "Market Cap.", width: 100, sortable: true},
58424 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58425 {header: "Employees", width: 100, sortable: true, resizable: false}
58430 * The config options listed for this class are options which may appear in each
58431 * individual column definition.
58432 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58434 * @param {Object} config An Array of column config objects. See this class's
58435 * config objects for details.
58437 Roo.grid.ColumnModel = function(config){
58439 * The config passed into the constructor
58441 this.config = []; //config;
58444 // if no id, create one
58445 // if the column does not have a dataIndex mapping,
58446 // map it to the order it is in the config
58447 for(var i = 0, len = config.length; i < len; i++){
58448 this.addColumn(config[i]);
58453 * The width of columns which have no width specified (defaults to 100)
58456 this.defaultWidth = 100;
58459 * Default sortable of columns which have no sortable specified (defaults to false)
58462 this.defaultSortable = false;
58466 * @event widthchange
58467 * Fires when the width of a column changes.
58468 * @param {ColumnModel} this
58469 * @param {Number} columnIndex The column index
58470 * @param {Number} newWidth The new width
58472 "widthchange": true,
58474 * @event headerchange
58475 * Fires when the text of a header changes.
58476 * @param {ColumnModel} this
58477 * @param {Number} columnIndex The column index
58478 * @param {Number} newText The new header text
58480 "headerchange": true,
58482 * @event hiddenchange
58483 * Fires when a column is hidden or "unhidden".
58484 * @param {ColumnModel} this
58485 * @param {Number} columnIndex The column index
58486 * @param {Boolean} hidden true if hidden, false otherwise
58488 "hiddenchange": true,
58490 * @event columnmoved
58491 * Fires when a column is moved.
58492 * @param {ColumnModel} this
58493 * @param {Number} oldIndex
58494 * @param {Number} newIndex
58496 "columnmoved" : true,
58498 * @event columlockchange
58499 * Fires when a column's locked state is changed
58500 * @param {ColumnModel} this
58501 * @param {Number} colIndex
58502 * @param {Boolean} locked true if locked
58504 "columnlockchange" : true
58506 Roo.grid.ColumnModel.superclass.constructor.call(this);
58508 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58510 * @cfg {String} header The header text to display in the Grid view.
58513 * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
58516 * @cfg {String} smHeader Header at Bootsrap Small width
58519 * @cfg {String} mdHeader Header at Bootsrap Medium width
58522 * @cfg {String} lgHeader Header at Bootsrap Large width
58525 * @cfg {String} xlHeader Header at Bootsrap extra Large width
58528 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58529 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58530 * specified, the column's index is used as an index into the Record's data Array.
58533 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58534 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58537 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58538 * Defaults to the value of the {@link #defaultSortable} property.
58539 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58542 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58545 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58548 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58551 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58554 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58555 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58556 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58557 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58560 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58563 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58566 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58569 * @cfg {String} cursor (Optional)
58572 * @cfg {String} tooltip (Optional)
58575 * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
58578 * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
58581 * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
58584 * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
58587 * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
58590 * Returns the id of the column at the specified index.
58591 * @param {Number} index The column index
58592 * @return {String} the id
58594 getColumnId : function(index){
58595 return this.config[index].id;
58599 * Returns the column for a specified id.
58600 * @param {String} id The column id
58601 * @return {Object} the column
58603 getColumnById : function(id){
58604 return this.lookup[id];
58609 * Returns the column Object for a specified dataIndex.
58610 * @param {String} dataIndex The column dataIndex
58611 * @return {Object|Boolean} the column or false if not found
58613 getColumnByDataIndex: function(dataIndex){
58614 var index = this.findColumnIndex(dataIndex);
58615 return index > -1 ? this.config[index] : false;
58619 * Returns the index for a specified column id.
58620 * @param {String} id The column id
58621 * @return {Number} the index, or -1 if not found
58623 getIndexById : function(id){
58624 for(var i = 0, len = this.config.length; i < len; i++){
58625 if(this.config[i].id == id){
58633 * Returns the index for a specified column dataIndex.
58634 * @param {String} dataIndex The column dataIndex
58635 * @return {Number} the index, or -1 if not found
58638 findColumnIndex : function(dataIndex){
58639 for(var i = 0, len = this.config.length; i < len; i++){
58640 if(this.config[i].dataIndex == dataIndex){
58648 moveColumn : function(oldIndex, newIndex){
58649 var c = this.config[oldIndex];
58650 this.config.splice(oldIndex, 1);
58651 this.config.splice(newIndex, 0, c);
58652 this.dataMap = null;
58653 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58656 isLocked : function(colIndex){
58657 return this.config[colIndex].locked === true;
58660 setLocked : function(colIndex, value, suppressEvent){
58661 if(this.isLocked(colIndex) == value){
58664 this.config[colIndex].locked = value;
58665 if(!suppressEvent){
58666 this.fireEvent("columnlockchange", this, colIndex, value);
58670 getTotalLockedWidth : function(){
58671 var totalWidth = 0;
58672 for(var i = 0; i < this.config.length; i++){
58673 if(this.isLocked(i) && !this.isHidden(i)){
58674 this.totalWidth += this.getColumnWidth(i);
58680 getLockedCount : function(){
58681 for(var i = 0, len = this.config.length; i < len; i++){
58682 if(!this.isLocked(i)){
58687 return this.config.length;
58691 * Returns the number of columns.
58694 getColumnCount : function(visibleOnly){
58695 if(visibleOnly === true){
58697 for(var i = 0, len = this.config.length; i < len; i++){
58698 if(!this.isHidden(i)){
58704 return this.config.length;
58708 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58709 * @param {Function} fn
58710 * @param {Object} scope (optional)
58711 * @return {Array} result
58713 getColumnsBy : function(fn, scope){
58715 for(var i = 0, len = this.config.length; i < len; i++){
58716 var c = this.config[i];
58717 if(fn.call(scope||this, c, i) === true){
58725 * Returns true if the specified column is sortable.
58726 * @param {Number} col The column index
58727 * @return {Boolean}
58729 isSortable : function(col){
58730 if(typeof this.config[col].sortable == "undefined"){
58731 return this.defaultSortable;
58733 return this.config[col].sortable;
58737 * Returns the rendering (formatting) function defined for the column.
58738 * @param {Number} col The column index.
58739 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58741 getRenderer : function(col){
58742 if(!this.config[col].renderer){
58743 return Roo.grid.ColumnModel.defaultRenderer;
58745 return this.config[col].renderer;
58749 * Sets the rendering (formatting) function for a column.
58750 * @param {Number} col The column index
58751 * @param {Function} fn The function to use to process the cell's raw data
58752 * to return HTML markup for the grid view. The render function is called with
58753 * the following parameters:<ul>
58754 * <li>Data value.</li>
58755 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58756 * <li>css A CSS style string to apply to the table cell.</li>
58757 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58758 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58759 * <li>Row index</li>
58760 * <li>Column index</li>
58761 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58763 setRenderer : function(col, fn){
58764 this.config[col].renderer = fn;
58768 * Returns the width for the specified column.
58769 * @param {Number} col The column index
58770 * @param (optional) {String} gridSize bootstrap width size.
58773 getColumnWidth : function(col, gridSize)
58775 var cfg = this.config[col];
58777 if (typeof(gridSize) == 'undefined') {
58778 return cfg.width * 1 || this.defaultWidth;
58780 if (gridSize === false) { // if we set it..
58781 return cfg.width || false;
58783 var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
58785 for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
58786 if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
58789 return cfg[ sizes[i] ];
58796 * Sets the width for a column.
58797 * @param {Number} col The column index
58798 * @param {Number} width The new width
58800 setColumnWidth : function(col, width, suppressEvent){
58801 this.config[col].width = width;
58802 this.totalWidth = null;
58803 if(!suppressEvent){
58804 this.fireEvent("widthchange", this, col, width);
58809 * Returns the total width of all columns.
58810 * @param {Boolean} includeHidden True to include hidden column widths
58813 getTotalWidth : function(includeHidden){
58814 if(!this.totalWidth){
58815 this.totalWidth = 0;
58816 for(var i = 0, len = this.config.length; i < len; i++){
58817 if(includeHidden || !this.isHidden(i)){
58818 this.totalWidth += this.getColumnWidth(i);
58822 return this.totalWidth;
58826 * Returns the header for the specified column.
58827 * @param {Number} col The column index
58830 getColumnHeader : function(col){
58831 return this.config[col].header;
58835 * Sets the header for a column.
58836 * @param {Number} col The column index
58837 * @param {String} header The new header
58839 setColumnHeader : function(col, header){
58840 this.config[col].header = header;
58841 this.fireEvent("headerchange", this, col, header);
58845 * Returns the tooltip for the specified column.
58846 * @param {Number} col The column index
58849 getColumnTooltip : function(col){
58850 return this.config[col].tooltip;
58853 * Sets the tooltip for a column.
58854 * @param {Number} col The column index
58855 * @param {String} tooltip The new tooltip
58857 setColumnTooltip : function(col, tooltip){
58858 this.config[col].tooltip = tooltip;
58862 * Returns the dataIndex for the specified column.
58863 * @param {Number} col The column index
58866 getDataIndex : function(col){
58867 return this.config[col].dataIndex;
58871 * Sets the dataIndex for a column.
58872 * @param {Number} col The column index
58873 * @param {Number} dataIndex The new dataIndex
58875 setDataIndex : function(col, dataIndex){
58876 this.config[col].dataIndex = dataIndex;
58882 * Returns true if the cell is editable.
58883 * @param {Number} colIndex The column index
58884 * @param {Number} rowIndex The row index - this is nto actually used..?
58885 * @return {Boolean}
58887 isCellEditable : function(colIndex, rowIndex){
58888 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58892 * Returns the editor defined for the cell/column.
58893 * return false or null to disable editing.
58894 * @param {Number} colIndex The column index
58895 * @param {Number} rowIndex The row index
58898 getCellEditor : function(colIndex, rowIndex){
58899 return this.config[colIndex].editor;
58903 * Sets if a column is editable.
58904 * @param {Number} col The column index
58905 * @param {Boolean} editable True if the column is editable
58907 setEditable : function(col, editable){
58908 this.config[col].editable = editable;
58913 * Returns true if the column is hidden.
58914 * @param {Number} colIndex The column index
58915 * @return {Boolean}
58917 isHidden : function(colIndex){
58918 return this.config[colIndex].hidden;
58923 * Returns true if the column width cannot be changed
58925 isFixed : function(colIndex){
58926 return this.config[colIndex].fixed;
58930 * Returns true if the column can be resized
58931 * @return {Boolean}
58933 isResizable : function(colIndex){
58934 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58937 * Sets if a column is hidden.
58938 * @param {Number} colIndex The column index
58939 * @param {Boolean} hidden True if the column is hidden
58941 setHidden : function(colIndex, hidden){
58942 this.config[colIndex].hidden = hidden;
58943 this.totalWidth = null;
58944 this.fireEvent("hiddenchange", this, colIndex, hidden);
58948 * Sets the editor for a column.
58949 * @param {Number} col The column index
58950 * @param {Object} editor The editor object
58952 setEditor : function(col, editor){
58953 this.config[col].editor = editor;
58956 * Add a column (experimental...) - defaults to adding to the end..
58957 * @param {Object} config
58959 addColumn : function(c)
58962 var i = this.config.length;
58963 this.config[i] = c;
58965 if(typeof c.dataIndex == "undefined"){
58968 if(typeof c.renderer == "string"){
58969 c.renderer = Roo.util.Format[c.renderer];
58971 if(typeof c.id == "undefined"){
58974 if(c.editor && c.editor.xtype){
58975 c.editor = Roo.factory(c.editor, Roo.grid);
58977 if(c.editor && c.editor.isFormField){
58978 c.editor = new Roo.grid.GridEditor(c.editor);
58980 this.lookup[c.id] = c;
58985 Roo.grid.ColumnModel.defaultRenderer = function(value)
58987 if(typeof value == "object") {
58990 if(typeof value == "string" && value.length < 1){
58994 return String.format("{0}", value);
58997 // Alias for backwards compatibility
58998 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
59001 * Ext JS Library 1.1.1
59002 * Copyright(c) 2006-2007, Ext JS, LLC.
59004 * Originally Released Under LGPL - original licence link has changed is not relivant.
59007 * <script type="text/javascript">
59011 * @class Roo.grid.AbstractSelectionModel
59012 * @extends Roo.util.Observable
59014 * Abstract base class for grid SelectionModels. It provides the interface that should be
59015 * implemented by descendant classes. This class should not be directly instantiated.
59018 Roo.grid.AbstractSelectionModel = function(){
59019 this.locked = false;
59020 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
59023 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
59024 /** @ignore Called by the grid automatically. Do not call directly. */
59025 init : function(grid){
59031 * Locks the selections.
59034 this.locked = true;
59038 * Unlocks the selections.
59040 unlock : function(){
59041 this.locked = false;
59045 * Returns true if the selections are locked.
59046 * @return {Boolean}
59048 isLocked : function(){
59049 return this.locked;
59053 * Ext JS Library 1.1.1
59054 * Copyright(c) 2006-2007, Ext JS, LLC.
59056 * Originally Released Under LGPL - original licence link has changed is not relivant.
59059 * <script type="text/javascript">
59062 * @extends Roo.grid.AbstractSelectionModel
59063 * @class Roo.grid.RowSelectionModel
59064 * The default SelectionModel used by {@link Roo.grid.Grid}.
59065 * It supports multiple selections and keyboard selection/navigation.
59067 * @param {Object} config
59069 Roo.grid.RowSelectionModel = function(config){
59070 Roo.apply(this, config);
59071 this.selections = new Roo.util.MixedCollection(false, function(o){
59076 this.lastActive = false;
59080 * @event selectionchange
59081 * Fires when the selection changes
59082 * @param {SelectionModel} this
59084 "selectionchange" : true,
59086 * @event afterselectionchange
59087 * Fires after the selection changes (eg. by key press or clicking)
59088 * @param {SelectionModel} this
59090 "afterselectionchange" : true,
59092 * @event beforerowselect
59093 * Fires when a row is selected being selected, return false to cancel.
59094 * @param {SelectionModel} this
59095 * @param {Number} rowIndex The selected index
59096 * @param {Boolean} keepExisting False if other selections will be cleared
59098 "beforerowselect" : true,
59101 * Fires when a row is selected.
59102 * @param {SelectionModel} this
59103 * @param {Number} rowIndex The selected index
59104 * @param {Roo.data.Record} r The record
59106 "rowselect" : true,
59108 * @event rowdeselect
59109 * Fires when a row is deselected.
59110 * @param {SelectionModel} this
59111 * @param {Number} rowIndex The selected index
59113 "rowdeselect" : true
59115 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
59116 this.locked = false;
59119 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
59121 * @cfg {Boolean} singleSelect
59122 * True to allow selection of only one row at a time (defaults to false)
59124 singleSelect : false,
59127 initEvents : function(){
59129 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
59130 this.grid.on("mousedown", this.handleMouseDown, this);
59131 }else{ // allow click to work like normal
59132 this.grid.on("rowclick", this.handleDragableRowClick, this);
59134 // bootstrap does not have a view..
59135 var view = this.grid.view ? this.grid.view : this.grid;
59136 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
59137 "up" : function(e){
59139 this.selectPrevious(e.shiftKey);
59140 }else if(this.last !== false && this.lastActive !== false){
59141 var last = this.last;
59142 this.selectRange(this.last, this.lastActive-1);
59143 view.focusRow(this.lastActive);
59144 if(last !== false){
59148 this.selectFirstRow();
59150 this.fireEvent("afterselectionchange", this);
59152 "down" : function(e){
59154 this.selectNext(e.shiftKey);
59155 }else if(this.last !== false && this.lastActive !== false){
59156 var last = this.last;
59157 this.selectRange(this.last, this.lastActive+1);
59158 view.focusRow(this.lastActive);
59159 if(last !== false){
59163 this.selectFirstRow();
59165 this.fireEvent("afterselectionchange", this);
59171 view.on("refresh", this.onRefresh, this);
59172 view.on("rowupdated", this.onRowUpdated, this);
59173 view.on("rowremoved", this.onRemove, this);
59177 onRefresh : function(){
59178 var ds = this.grid.ds, i, v = this.grid.view;
59179 var s = this.selections;
59180 s.each(function(r){
59181 if((i = ds.indexOfId(r.id)) != -1){
59183 s.add(ds.getAt(i)); // updating the selection relate data
59191 onRemove : function(v, index, r){
59192 this.selections.remove(r);
59196 onRowUpdated : function(v, index, r){
59197 if(this.isSelected(r)){
59198 v.onRowSelect(index);
59204 * @param {Array} records The records to select
59205 * @param {Boolean} keepExisting (optional) True to keep existing selections
59207 selectRecords : function(records, keepExisting){
59209 this.clearSelections();
59211 var ds = this.grid.ds;
59212 for(var i = 0, len = records.length; i < len; i++){
59213 this.selectRow(ds.indexOf(records[i]), true);
59218 * Gets the number of selected rows.
59221 getCount : function(){
59222 return this.selections.length;
59226 * Selects the first row in the grid.
59228 selectFirstRow : function(){
59233 * Select the last row.
59234 * @param {Boolean} keepExisting (optional) True to keep existing selections
59236 selectLastRow : function(keepExisting){
59237 this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
59241 * Selects the row immediately following the last selected row.
59242 * @param {Boolean} keepExisting (optional) True to keep existing selections
59244 selectNext : function(keepExisting){
59245 if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
59246 this.selectRow(this.last+1, keepExisting);
59247 var view = this.grid.view ? this.grid.view : this.grid;
59248 view.focusRow(this.last);
59253 * Selects the row that precedes the last selected row.
59254 * @param {Boolean} keepExisting (optional) True to keep existing selections
59256 selectPrevious : function(keepExisting){
59258 this.selectRow(this.last-1, keepExisting);
59259 var view = this.grid.view ? this.grid.view : this.grid;
59260 view.focusRow(this.last);
59265 * Returns the selected records
59266 * @return {Array} Array of selected records
59268 getSelections : function(){
59269 return [].concat(this.selections.items);
59273 * Returns the first selected record.
59276 getSelected : function(){
59277 return this.selections.itemAt(0);
59282 * Clears all selections.
59284 clearSelections : function(fast){
59289 var ds = this.grid.ds;
59290 var s = this.selections;
59291 s.each(function(r){
59292 this.deselectRow(ds.indexOfId(r.id));
59296 this.selections.clear();
59303 * Selects all rows.
59305 selectAll : function(){
59309 this.selections.clear();
59310 for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
59311 this.selectRow(i, true);
59316 * Returns True if there is a selection.
59317 * @return {Boolean}
59319 hasSelection : function(){
59320 return this.selections.length > 0;
59324 * Returns True if the specified row is selected.
59325 * @param {Number/Record} record The record or index of the record to check
59326 * @return {Boolean}
59328 isSelected : function(index){
59329 var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
59330 return (r && this.selections.key(r.id) ? true : false);
59334 * Returns True if the specified record id is selected.
59335 * @param {String} id The id of record to check
59336 * @return {Boolean}
59338 isIdSelected : function(id){
59339 return (this.selections.key(id) ? true : false);
59343 handleMouseDown : function(e, t)
59345 var view = this.grid.view ? this.grid.view : this.grid;
59347 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
59350 if(e.shiftKey && this.last !== false){
59351 var last = this.last;
59352 this.selectRange(last, rowIndex, e.ctrlKey);
59353 this.last = last; // reset the last
59354 view.focusRow(rowIndex);
59356 var isSelected = this.isSelected(rowIndex);
59357 if(e.button !== 0 && isSelected){
59358 view.focusRow(rowIndex);
59359 }else if(e.ctrlKey && isSelected){
59360 this.deselectRow(rowIndex);
59361 }else if(!isSelected){
59362 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
59363 view.focusRow(rowIndex);
59366 this.fireEvent("afterselectionchange", this);
59369 handleDragableRowClick : function(grid, rowIndex, e)
59371 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
59372 this.selectRow(rowIndex, false);
59373 var view = this.grid.view ? this.grid.view : this.grid;
59374 view.focusRow(rowIndex);
59375 this.fireEvent("afterselectionchange", this);
59380 * Selects multiple rows.
59381 * @param {Array} rows Array of the indexes of the row to select
59382 * @param {Boolean} keepExisting (optional) True to keep existing selections
59384 selectRows : function(rows, keepExisting){
59386 this.clearSelections();
59388 for(var i = 0, len = rows.length; i < len; i++){
59389 this.selectRow(rows[i], true);
59394 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59395 * @param {Number} startRow The index of the first row in the range
59396 * @param {Number} endRow The index of the last row in the range
59397 * @param {Boolean} keepExisting (optional) True to retain existing selections
59399 selectRange : function(startRow, endRow, keepExisting){
59404 this.clearSelections();
59406 if(startRow <= endRow){
59407 for(var i = startRow; i <= endRow; i++){
59408 this.selectRow(i, true);
59411 for(var i = startRow; i >= endRow; i--){
59412 this.selectRow(i, true);
59418 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59419 * @param {Number} startRow The index of the first row in the range
59420 * @param {Number} endRow The index of the last row in the range
59422 deselectRange : function(startRow, endRow, preventViewNotify){
59426 for(var i = startRow; i <= endRow; i++){
59427 this.deselectRow(i, preventViewNotify);
59433 * @param {Number} row The index of the row to select
59434 * @param {Boolean} keepExisting (optional) True to keep existing selections
59436 selectRow : function(index, keepExisting, preventViewNotify){
59437 if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
59440 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59441 if(!keepExisting || this.singleSelect){
59442 this.clearSelections();
59444 var r = this.grid.ds.getAt(index);
59445 this.selections.add(r);
59446 this.last = this.lastActive = index;
59447 if(!preventViewNotify){
59448 var view = this.grid.view ? this.grid.view : this.grid;
59449 view.onRowSelect(index);
59451 this.fireEvent("rowselect", this, index, r);
59452 this.fireEvent("selectionchange", this);
59458 * @param {Number} row The index of the row to deselect
59460 deselectRow : function(index, preventViewNotify){
59464 if(this.last == index){
59467 if(this.lastActive == index){
59468 this.lastActive = false;
59470 var r = this.grid.ds.getAt(index);
59471 this.selections.remove(r);
59472 if(!preventViewNotify){
59473 var view = this.grid.view ? this.grid.view : this.grid;
59474 view.onRowDeselect(index);
59476 this.fireEvent("rowdeselect", this, index);
59477 this.fireEvent("selectionchange", this);
59481 restoreLast : function(){
59483 this.last = this._last;
59488 acceptsNav : function(row, col, cm){
59489 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59493 onEditorKey : function(field, e){
59494 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59499 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59501 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59503 }else if(k == e.ENTER && !e.ctrlKey){
59507 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59509 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59511 }else if(k == e.ESC){
59515 g.startEditing(newCell[0], newCell[1]);
59520 * Ext JS Library 1.1.1
59521 * Copyright(c) 2006-2007, Ext JS, LLC.
59523 * Originally Released Under LGPL - original licence link has changed is not relivant.
59526 * <script type="text/javascript">
59529 * @class Roo.grid.CellSelectionModel
59530 * @extends Roo.grid.AbstractSelectionModel
59531 * This class provides the basic implementation for cell selection in a grid.
59533 * @param {Object} config The object containing the configuration of this model.
59534 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59536 Roo.grid.CellSelectionModel = function(config){
59537 Roo.apply(this, config);
59539 this.selection = null;
59543 * @event beforerowselect
59544 * Fires before a cell is selected.
59545 * @param {SelectionModel} this
59546 * @param {Number} rowIndex The selected row index
59547 * @param {Number} colIndex The selected cell index
59549 "beforecellselect" : true,
59551 * @event cellselect
59552 * Fires when a cell is selected.
59553 * @param {SelectionModel} this
59554 * @param {Number} rowIndex The selected row index
59555 * @param {Number} colIndex The selected cell index
59557 "cellselect" : true,
59559 * @event selectionchange
59560 * Fires when the active selection changes.
59561 * @param {SelectionModel} this
59562 * @param {Object} selection null for no selection or an object (o) with two properties
59564 <li>o.record: the record object for the row the selection is in</li>
59565 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59568 "selectionchange" : true,
59571 * Fires when the tab (or enter) was pressed on the last editable cell
59572 * You can use this to trigger add new row.
59573 * @param {SelectionModel} this
59577 * @event beforeeditnext
59578 * Fires before the next editable sell is made active
59579 * You can use this to skip to another cell or fire the tabend
59580 * if you set cell to false
59581 * @param {Object} eventdata object : { cell : [ row, col ] }
59583 "beforeeditnext" : true
59585 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59588 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59590 enter_is_tab: false,
59593 initEvents : function(){
59594 this.grid.on("mousedown", this.handleMouseDown, this);
59595 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59596 var view = this.grid.view;
59597 view.on("refresh", this.onViewChange, this);
59598 view.on("rowupdated", this.onRowUpdated, this);
59599 view.on("beforerowremoved", this.clearSelections, this);
59600 view.on("beforerowsinserted", this.clearSelections, this);
59601 if(this.grid.isEditor){
59602 this.grid.on("beforeedit", this.beforeEdit, this);
59607 beforeEdit : function(e){
59608 this.select(e.row, e.column, false, true, e.record);
59612 onRowUpdated : function(v, index, r){
59613 if(this.selection && this.selection.record == r){
59614 v.onCellSelect(index, this.selection.cell[1]);
59619 onViewChange : function(){
59620 this.clearSelections(true);
59624 * Returns the currently selected cell,.
59625 * @return {Array} The selected cell (row, column) or null if none selected.
59627 getSelectedCell : function(){
59628 return this.selection ? this.selection.cell : null;
59632 * Clears all selections.
59633 * @param {Boolean} true to prevent the gridview from being notified about the change.
59635 clearSelections : function(preventNotify){
59636 var s = this.selection;
59638 if(preventNotify !== true){
59639 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59641 this.selection = null;
59642 this.fireEvent("selectionchange", this, null);
59647 * Returns true if there is a selection.
59648 * @return {Boolean}
59650 hasSelection : function(){
59651 return this.selection ? true : false;
59655 handleMouseDown : function(e, t){
59656 var v = this.grid.getView();
59657 if(this.isLocked()){
59660 var row = v.findRowIndex(t);
59661 var cell = v.findCellIndex(t);
59662 if(row !== false && cell !== false){
59663 this.select(row, cell);
59669 * @param {Number} rowIndex
59670 * @param {Number} collIndex
59672 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59673 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59674 this.clearSelections();
59675 r = r || this.grid.dataSource.getAt(rowIndex);
59678 cell : [rowIndex, colIndex]
59680 if(!preventViewNotify){
59681 var v = this.grid.getView();
59682 v.onCellSelect(rowIndex, colIndex);
59683 if(preventFocus !== true){
59684 v.focusCell(rowIndex, colIndex);
59687 this.fireEvent("cellselect", this, rowIndex, colIndex);
59688 this.fireEvent("selectionchange", this, this.selection);
59693 isSelectable : function(rowIndex, colIndex, cm){
59694 return !cm.isHidden(colIndex);
59698 handleKeyDown : function(e){
59699 //Roo.log('Cell Sel Model handleKeyDown');
59700 if(!e.isNavKeyPress()){
59703 var g = this.grid, s = this.selection;
59706 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59708 this.select(cell[0], cell[1]);
59713 var walk = function(row, col, step){
59714 return g.walkCells(row, col, step, sm.isSelectable, sm);
59716 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59723 // handled by onEditorKey
59724 if (g.isEditor && g.editing) {
59728 newCell = walk(r, c-1, -1);
59730 newCell = walk(r, c+1, 1);
59735 newCell = walk(r+1, c, 1);
59739 newCell = walk(r-1, c, -1);
59743 newCell = walk(r, c+1, 1);
59747 newCell = walk(r, c-1, -1);
59752 if(g.isEditor && !g.editing){
59753 g.startEditing(r, c);
59762 this.select(newCell[0], newCell[1]);
59768 acceptsNav : function(row, col, cm){
59769 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59773 * @param {Number} field (not used) - as it's normally used as a listener
59774 * @param {Number} e - event - fake it by using
59776 * var e = Roo.EventObjectImpl.prototype;
59777 * e.keyCode = e.TAB
59781 onEditorKey : function(field, e){
59783 var k = e.getKey(),
59786 ed = g.activeEditor,
59788 ///Roo.log('onEditorKey' + k);
59791 if (this.enter_is_tab && k == e.ENTER) {
59797 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59799 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59805 } else if(k == e.ENTER && !e.ctrlKey){
59808 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59810 } else if(k == e.ESC){
59815 var ecall = { cell : newCell, forward : forward };
59816 this.fireEvent('beforeeditnext', ecall );
59817 newCell = ecall.cell;
59818 forward = ecall.forward;
59822 //Roo.log('next cell after edit');
59823 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59824 } else if (forward) {
59825 // tabbed past last
59826 this.fireEvent.defer(100, this, ['tabend',this]);
59831 * Ext JS Library 1.1.1
59832 * Copyright(c) 2006-2007, Ext JS, LLC.
59834 * Originally Released Under LGPL - original licence link has changed is not relivant.
59837 * <script type="text/javascript">
59841 * @class Roo.grid.EditorGrid
59842 * @extends Roo.grid.Grid
59843 * Class for creating and editable grid.
59844 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59845 * The container MUST have some type of size defined for the grid to fill. The container will be
59846 * automatically set to position relative if it isn't already.
59847 * @param {Object} dataSource The data model to bind to
59848 * @param {Object} colModel The column model with info about this grid's columns
59850 Roo.grid.EditorGrid = function(container, config){
59851 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59852 this.getGridEl().addClass("xedit-grid");
59854 if(!this.selModel){
59855 this.selModel = new Roo.grid.CellSelectionModel();
59858 this.activeEditor = null;
59862 * @event beforeedit
59863 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59864 * <ul style="padding:5px;padding-left:16px;">
59865 * <li>grid - This grid</li>
59866 * <li>record - The record being edited</li>
59867 * <li>field - The field name being edited</li>
59868 * <li>value - The value for the field being edited.</li>
59869 * <li>row - The grid row index</li>
59870 * <li>column - The grid column index</li>
59871 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59873 * @param {Object} e An edit event (see above for description)
59875 "beforeedit" : true,
59878 * Fires after a cell is edited. <br />
59879 * <ul style="padding:5px;padding-left:16px;">
59880 * <li>grid - This grid</li>
59881 * <li>record - The record being edited</li>
59882 * <li>field - The field name being edited</li>
59883 * <li>value - The value being set</li>
59884 * <li>originalValue - The original value for the field, before the edit.</li>
59885 * <li>row - The grid row index</li>
59886 * <li>column - The grid column index</li>
59888 * @param {Object} e An edit event (see above for description)
59890 "afteredit" : true,
59892 * @event validateedit
59893 * Fires after a cell is edited, but before the value is set in the record.
59894 * You can use this to modify the value being set in the field, Return false
59895 * to cancel the change. The edit event object has the following properties <br />
59896 * <ul style="padding:5px;padding-left:16px;">
59897 * <li>editor - This editor</li>
59898 * <li>grid - This grid</li>
59899 * <li>record - The record being edited</li>
59900 * <li>field - The field name being edited</li>
59901 * <li>value - The value being set</li>
59902 * <li>originalValue - The original value for the field, before the edit.</li>
59903 * <li>row - The grid row index</li>
59904 * <li>column - The grid column index</li>
59905 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59907 * @param {Object} e An edit event (see above for description)
59909 "validateedit" : true
59911 this.on("bodyscroll", this.stopEditing, this);
59912 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59915 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59917 * @cfg {Number} clicksToEdit
59918 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59925 trackMouseOver: false, // causes very odd FF errors
59927 onCellDblClick : function(g, row, col){
59928 this.startEditing(row, col);
59931 onEditComplete : function(ed, value, startValue){
59932 this.editing = false;
59933 this.activeEditor = null;
59934 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59936 var field = this.colModel.getDataIndex(ed.col);
59941 originalValue: startValue,
59948 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59951 if(String(value) !== String(startValue)){
59953 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59954 r.set(field, e.value);
59955 // if we are dealing with a combo box..
59956 // then we also set the 'name' colum to be the displayField
59957 if (ed.field.displayField && ed.field.name) {
59958 r.set(ed.field.name, ed.field.el.dom.value);
59961 delete e.cancel; //?? why!!!
59962 this.fireEvent("afteredit", e);
59965 this.fireEvent("afteredit", e); // always fire it!
59967 this.view.focusCell(ed.row, ed.col);
59971 * Starts editing the specified for the specified row/column
59972 * @param {Number} rowIndex
59973 * @param {Number} colIndex
59975 startEditing : function(row, col){
59976 this.stopEditing();
59977 if(this.colModel.isCellEditable(col, row)){
59978 this.view.ensureVisible(row, col, true);
59980 var r = this.dataSource.getAt(row);
59981 var field = this.colModel.getDataIndex(col);
59982 var cell = Roo.get(this.view.getCell(row,col));
59987 value: r.data[field],
59992 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59993 this.editing = true;
59994 var ed = this.colModel.getCellEditor(col, row);
60000 ed.render(ed.parentEl || document.body);
60006 (function(){ // complex but required for focus issues in safari, ie and opera
60010 ed.on("complete", this.onEditComplete, this, {single: true});
60011 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
60012 this.activeEditor = ed;
60013 var v = r.data[field];
60014 ed.startEdit(this.view.getCell(row, col), v);
60015 // combo's with 'displayField and name set
60016 if (ed.field.displayField && ed.field.name) {
60017 ed.field.el.dom.value = r.data[ed.field.name];
60021 }).defer(50, this);
60027 * Stops any active editing
60029 stopEditing : function(){
60030 if(this.activeEditor){
60031 this.activeEditor.completeEdit();
60033 this.activeEditor = null;
60037 * Called to get grid's drag proxy text, by default returns this.ddText.
60040 getDragDropText : function(){
60041 var count = this.selModel.getSelectedCell() ? 1 : 0;
60042 return String.format(this.ddText, count, count == 1 ? '' : 's');
60047 * Ext JS Library 1.1.1
60048 * Copyright(c) 2006-2007, Ext JS, LLC.
60050 * Originally Released Under LGPL - original licence link has changed is not relivant.
60053 * <script type="text/javascript">
60056 // private - not really -- you end up using it !
60057 // This is a support class used internally by the Grid components
60060 * @class Roo.grid.GridEditor
60061 * @extends Roo.Editor
60062 * Class for creating and editable grid elements.
60063 * @param {Object} config any settings (must include field)
60065 Roo.grid.GridEditor = function(field, config){
60066 if (!config && field.field) {
60068 field = Roo.factory(config.field, Roo.form);
60070 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
60071 field.monitorTab = false;
60074 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
60077 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
60080 alignment: "tl-tl",
60083 cls: "x-small-editor x-grid-editor",
60088 * Ext JS Library 1.1.1
60089 * Copyright(c) 2006-2007, Ext JS, LLC.
60091 * Originally Released Under LGPL - original licence link has changed is not relivant.
60094 * <script type="text/javascript">
60099 Roo.grid.PropertyRecord = Roo.data.Record.create([
60100 {name:'name',type:'string'}, 'value'
60104 Roo.grid.PropertyStore = function(grid, source){
60106 this.store = new Roo.data.Store({
60107 recordType : Roo.grid.PropertyRecord
60109 this.store.on('update', this.onUpdate, this);
60111 this.setSource(source);
60113 Roo.grid.PropertyStore.superclass.constructor.call(this);
60118 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
60119 setSource : function(o){
60121 this.store.removeAll();
60124 if(this.isEditableValue(o[k])){
60125 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
60128 this.store.loadRecords({records: data}, {}, true);
60131 onUpdate : function(ds, record, type){
60132 if(type == Roo.data.Record.EDIT){
60133 var v = record.data['value'];
60134 var oldValue = record.modified['value'];
60135 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
60136 this.source[record.id] = v;
60138 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
60145 getProperty : function(row){
60146 return this.store.getAt(row);
60149 isEditableValue: function(val){
60150 if(val && val instanceof Date){
60152 }else if(typeof val == 'object' || typeof val == 'function'){
60158 setValue : function(prop, value){
60159 this.source[prop] = value;
60160 this.store.getById(prop).set('value', value);
60163 getSource : function(){
60164 return this.source;
60168 Roo.grid.PropertyColumnModel = function(grid, store){
60171 g.PropertyColumnModel.superclass.constructor.call(this, [
60172 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
60173 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
60175 this.store = store;
60176 this.bselect = Roo.DomHelper.append(document.body, {
60177 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
60178 {tag: 'option', value: 'true', html: 'true'},
60179 {tag: 'option', value: 'false', html: 'false'}
60182 Roo.id(this.bselect);
60185 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
60186 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
60187 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
60188 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
60189 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
60191 this.renderCellDelegate = this.renderCell.createDelegate(this);
60192 this.renderPropDelegate = this.renderProp.createDelegate(this);
60195 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
60199 valueText : 'Value',
60201 dateFormat : 'm/j/Y',
60204 renderDate : function(dateVal){
60205 return dateVal.dateFormat(this.dateFormat);
60208 renderBool : function(bVal){
60209 return bVal ? 'true' : 'false';
60212 isCellEditable : function(colIndex, rowIndex){
60213 return colIndex == 1;
60216 getRenderer : function(col){
60218 this.renderCellDelegate : this.renderPropDelegate;
60221 renderProp : function(v){
60222 return this.getPropertyName(v);
60225 renderCell : function(val){
60227 if(val instanceof Date){
60228 rv = this.renderDate(val);
60229 }else if(typeof val == 'boolean'){
60230 rv = this.renderBool(val);
60232 return Roo.util.Format.htmlEncode(rv);
60235 getPropertyName : function(name){
60236 var pn = this.grid.propertyNames;
60237 return pn && pn[name] ? pn[name] : name;
60240 getCellEditor : function(colIndex, rowIndex){
60241 var p = this.store.getProperty(rowIndex);
60242 var n = p.data['name'], val = p.data['value'];
60244 if(typeof(this.grid.customEditors[n]) == 'string'){
60245 return this.editors[this.grid.customEditors[n]];
60247 if(typeof(this.grid.customEditors[n]) != 'undefined'){
60248 return this.grid.customEditors[n];
60250 if(val instanceof Date){
60251 return this.editors['date'];
60252 }else if(typeof val == 'number'){
60253 return this.editors['number'];
60254 }else if(typeof val == 'boolean'){
60255 return this.editors['boolean'];
60257 return this.editors['string'];
60263 * @class Roo.grid.PropertyGrid
60264 * @extends Roo.grid.EditorGrid
60265 * This class represents the interface of a component based property grid control.
60266 * <br><br>Usage:<pre><code>
60267 var grid = new Roo.grid.PropertyGrid("my-container-id", {
60275 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60276 * The container MUST have some type of size defined for the grid to fill. The container will be
60277 * automatically set to position relative if it isn't already.
60278 * @param {Object} config A config object that sets properties on this grid.
60280 Roo.grid.PropertyGrid = function(container, config){
60281 config = config || {};
60282 var store = new Roo.grid.PropertyStore(this);
60283 this.store = store;
60284 var cm = new Roo.grid.PropertyColumnModel(this, store);
60285 store.store.sort('name', 'ASC');
60286 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
60289 enableColLock:false,
60290 enableColumnMove:false,
60292 trackMouseOver: false,
60295 this.getGridEl().addClass('x-props-grid');
60296 this.lastEditRow = null;
60297 this.on('columnresize', this.onColumnResize, this);
60300 * @event beforepropertychange
60301 * Fires before a property changes (return false to stop?)
60302 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60303 * @param {String} id Record Id
60304 * @param {String} newval New Value
60305 * @param {String} oldval Old Value
60307 "beforepropertychange": true,
60309 * @event propertychange
60310 * Fires after a property changes
60311 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60312 * @param {String} id Record Id
60313 * @param {String} newval New Value
60314 * @param {String} oldval Old Value
60316 "propertychange": true
60318 this.customEditors = this.customEditors || {};
60320 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
60323 * @cfg {Object} customEditors map of colnames=> custom editors.
60324 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
60325 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
60326 * false disables editing of the field.
60330 * @cfg {Object} propertyNames map of property Names to their displayed value
60333 render : function(){
60334 Roo.grid.PropertyGrid.superclass.render.call(this);
60335 this.autoSize.defer(100, this);
60338 autoSize : function(){
60339 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
60341 this.view.fitColumns();
60345 onColumnResize : function(){
60346 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
60350 * Sets the data for the Grid
60351 * accepts a Key => Value object of all the elements avaiable.
60352 * @param {Object} data to appear in grid.
60354 setSource : function(source){
60355 this.store.setSource(source);
60359 * Gets all the data from the grid.
60360 * @return {Object} data data stored in grid
60362 getSource : function(){
60363 return this.store.getSource();
60372 * @class Roo.grid.Calendar
60373 * @extends Roo.grid.Grid
60374 * This class extends the Grid to provide a calendar widget
60375 * <br><br>Usage:<pre><code>
60376 var grid = new Roo.grid.Calendar("my-container-id", {
60379 selModel: mySelectionModel,
60380 autoSizeColumns: true,
60381 monitorWindowResize: false,
60382 trackMouseOver: true
60383 eventstore : real data store..
60389 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60390 * The container MUST have some type of size defined for the grid to fill. The container will be
60391 * automatically set to position relative if it isn't already.
60392 * @param {Object} config A config object that sets properties on this grid.
60394 Roo.grid.Calendar = function(container, config){
60395 // initialize the container
60396 this.container = Roo.get(container);
60397 this.container.update("");
60398 this.container.setStyle("overflow", "hidden");
60399 this.container.addClass('x-grid-container');
60401 this.id = this.container.id;
60403 Roo.apply(this, config);
60404 // check and correct shorthanded configs
60408 for (var r = 0;r < 6;r++) {
60411 for (var c =0;c < 7;c++) {
60415 if (this.eventStore) {
60416 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60417 this.eventStore.on('load',this.onLoad, this);
60418 this.eventStore.on('beforeload',this.clearEvents, this);
60422 this.dataSource = new Roo.data.Store({
60423 proxy: new Roo.data.MemoryProxy(rows),
60424 reader: new Roo.data.ArrayReader({}, [
60425 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60428 this.dataSource.load();
60429 this.ds = this.dataSource;
60430 this.ds.xmodule = this.xmodule || false;
60433 var cellRender = function(v,x,r)
60435 return String.format(
60436 '<div class="fc-day fc-widget-content"><div>' +
60437 '<div class="fc-event-container"></div>' +
60438 '<div class="fc-day-number">{0}</div>'+
60440 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60441 '</div></div>', v);
60446 this.colModel = new Roo.grid.ColumnModel( [
60448 xtype: 'ColumnModel',
60450 dataIndex : 'weekday0',
60452 renderer : cellRender
60455 xtype: 'ColumnModel',
60457 dataIndex : 'weekday1',
60459 renderer : cellRender
60462 xtype: 'ColumnModel',
60464 dataIndex : 'weekday2',
60465 header : 'Tuesday',
60466 renderer : cellRender
60469 xtype: 'ColumnModel',
60471 dataIndex : 'weekday3',
60472 header : 'Wednesday',
60473 renderer : cellRender
60476 xtype: 'ColumnModel',
60478 dataIndex : 'weekday4',
60479 header : 'Thursday',
60480 renderer : cellRender
60483 xtype: 'ColumnModel',
60485 dataIndex : 'weekday5',
60487 renderer : cellRender
60490 xtype: 'ColumnModel',
60492 dataIndex : 'weekday6',
60493 header : 'Saturday',
60494 renderer : cellRender
60497 this.cm = this.colModel;
60498 this.cm.xmodule = this.xmodule || false;
60502 //this.selModel = new Roo.grid.CellSelectionModel();
60503 //this.sm = this.selModel;
60504 //this.selModel.init(this);
60508 this.container.setWidth(this.width);
60512 this.container.setHeight(this.height);
60519 * The raw click event for the entire grid.
60520 * @param {Roo.EventObject} e
60525 * The raw dblclick event for the entire grid.
60526 * @param {Roo.EventObject} e
60530 * @event contextmenu
60531 * The raw contextmenu event for the entire grid.
60532 * @param {Roo.EventObject} e
60534 "contextmenu" : true,
60537 * The raw mousedown event for the entire grid.
60538 * @param {Roo.EventObject} e
60540 "mousedown" : true,
60543 * The raw mouseup event for the entire grid.
60544 * @param {Roo.EventObject} e
60549 * The raw mouseover event for the entire grid.
60550 * @param {Roo.EventObject} e
60552 "mouseover" : true,
60555 * The raw mouseout event for the entire grid.
60556 * @param {Roo.EventObject} e
60561 * The raw keypress event for the entire grid.
60562 * @param {Roo.EventObject} e
60567 * The raw keydown event for the entire grid.
60568 * @param {Roo.EventObject} e
60576 * Fires when a cell is clicked
60577 * @param {Grid} this
60578 * @param {Number} rowIndex
60579 * @param {Number} columnIndex
60580 * @param {Roo.EventObject} e
60582 "cellclick" : true,
60584 * @event celldblclick
60585 * Fires when a cell is double clicked
60586 * @param {Grid} this
60587 * @param {Number} rowIndex
60588 * @param {Number} columnIndex
60589 * @param {Roo.EventObject} e
60591 "celldblclick" : true,
60594 * Fires when a row is clicked
60595 * @param {Grid} this
60596 * @param {Number} rowIndex
60597 * @param {Roo.EventObject} e
60601 * @event rowdblclick
60602 * Fires when a row is double clicked
60603 * @param {Grid} this
60604 * @param {Number} rowIndex
60605 * @param {Roo.EventObject} e
60607 "rowdblclick" : true,
60609 * @event headerclick
60610 * Fires when a header is clicked
60611 * @param {Grid} this
60612 * @param {Number} columnIndex
60613 * @param {Roo.EventObject} e
60615 "headerclick" : true,
60617 * @event headerdblclick
60618 * Fires when a header cell is double clicked
60619 * @param {Grid} this
60620 * @param {Number} columnIndex
60621 * @param {Roo.EventObject} e
60623 "headerdblclick" : true,
60625 * @event rowcontextmenu
60626 * Fires when a row is right clicked
60627 * @param {Grid} this
60628 * @param {Number} rowIndex
60629 * @param {Roo.EventObject} e
60631 "rowcontextmenu" : true,
60633 * @event cellcontextmenu
60634 * Fires when a cell is right clicked
60635 * @param {Grid} this
60636 * @param {Number} rowIndex
60637 * @param {Number} cellIndex
60638 * @param {Roo.EventObject} e
60640 "cellcontextmenu" : true,
60642 * @event headercontextmenu
60643 * Fires when a header is right clicked
60644 * @param {Grid} this
60645 * @param {Number} columnIndex
60646 * @param {Roo.EventObject} e
60648 "headercontextmenu" : true,
60650 * @event bodyscroll
60651 * Fires when the body element is scrolled
60652 * @param {Number} scrollLeft
60653 * @param {Number} scrollTop
60655 "bodyscroll" : true,
60657 * @event columnresize
60658 * Fires when the user resizes a column
60659 * @param {Number} columnIndex
60660 * @param {Number} newSize
60662 "columnresize" : true,
60664 * @event columnmove
60665 * Fires when the user moves a column
60666 * @param {Number} oldIndex
60667 * @param {Number} newIndex
60669 "columnmove" : true,
60672 * Fires when row(s) start being dragged
60673 * @param {Grid} this
60674 * @param {Roo.GridDD} dd The drag drop object
60675 * @param {event} e The raw browser event
60677 "startdrag" : true,
60680 * Fires when a drag operation is complete
60681 * @param {Grid} this
60682 * @param {Roo.GridDD} dd The drag drop object
60683 * @param {event} e The raw browser event
60688 * Fires when dragged row(s) are dropped on a valid DD target
60689 * @param {Grid} this
60690 * @param {Roo.GridDD} dd The drag drop object
60691 * @param {String} targetId The target drag drop object
60692 * @param {event} e The raw browser event
60697 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60698 * @param {Grid} this
60699 * @param {Roo.GridDD} dd The drag drop object
60700 * @param {String} targetId The target drag drop object
60701 * @param {event} e The raw browser event
60706 * Fires when the dragged row(s) first cross another DD target while being dragged
60707 * @param {Grid} this
60708 * @param {Roo.GridDD} dd The drag drop object
60709 * @param {String} targetId The target drag drop object
60710 * @param {event} e The raw browser event
60712 "dragenter" : true,
60715 * Fires when the dragged row(s) leave another DD target while being dragged
60716 * @param {Grid} this
60717 * @param {Roo.GridDD} dd The drag drop object
60718 * @param {String} targetId The target drag drop object
60719 * @param {event} e The raw browser event
60724 * Fires when a row is rendered, so you can change add a style to it.
60725 * @param {GridView} gridview The grid view
60726 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60732 * Fires when the grid is rendered
60733 * @param {Grid} grid
60738 * Fires when a date is selected
60739 * @param {DatePicker} this
60740 * @param {Date} date The selected date
60744 * @event monthchange
60745 * Fires when the displayed month changes
60746 * @param {DatePicker} this
60747 * @param {Date} date The selected month
60749 'monthchange': true,
60751 * @event evententer
60752 * Fires when mouse over an event
60753 * @param {Calendar} this
60754 * @param {event} Event
60756 'evententer': true,
60758 * @event eventleave
60759 * Fires when the mouse leaves an
60760 * @param {Calendar} this
60763 'eventleave': true,
60765 * @event eventclick
60766 * Fires when the mouse click an
60767 * @param {Calendar} this
60770 'eventclick': true,
60772 * @event eventrender
60773 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60774 * @param {Calendar} this
60775 * @param {data} data to be modified
60777 'eventrender': true
60781 Roo.grid.Grid.superclass.constructor.call(this);
60782 this.on('render', function() {
60783 this.view.el.addClass('x-grid-cal');
60785 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60789 if (!Roo.grid.Calendar.style) {
60790 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60793 '.x-grid-cal .x-grid-col' : {
60794 height: 'auto !important',
60795 'vertical-align': 'top'
60797 '.x-grid-cal .fc-event-hori' : {
60808 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60810 * @cfg {Store} eventStore The store that loads events.
60815 activeDate : false,
60818 monitorWindowResize : false,
60821 resizeColumns : function() {
60822 var col = (this.view.el.getWidth() / 7) - 3;
60823 // loop through cols, and setWidth
60824 for(var i =0 ; i < 7 ; i++){
60825 this.cm.setColumnWidth(i, col);
60828 setDate :function(date) {
60830 Roo.log('setDate?');
60832 this.resizeColumns();
60833 var vd = this.activeDate;
60834 this.activeDate = date;
60835 // if(vd && this.el){
60836 // var t = date.getTime();
60837 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60838 // Roo.log('using add remove');
60840 // this.fireEvent('monthchange', this, date);
60842 // this.cells.removeClass("fc-state-highlight");
60843 // this.cells.each(function(c){
60844 // if(c.dateValue == t){
60845 // c.addClass("fc-state-highlight");
60846 // setTimeout(function(){
60847 // try{c.dom.firstChild.focus();}catch(e){}
60857 var days = date.getDaysInMonth();
60859 var firstOfMonth = date.getFirstDateOfMonth();
60860 var startingPos = firstOfMonth.getDay()-this.startDay;
60862 if(startingPos < this.startDay){
60866 var pm = date.add(Date.MONTH, -1);
60867 var prevStart = pm.getDaysInMonth()-startingPos;
60871 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60873 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60874 //this.cells.addClassOnOver('fc-state-hover');
60876 var cells = this.cells.elements;
60877 var textEls = this.textNodes;
60879 //Roo.each(cells, function(cell){
60880 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60883 days += startingPos;
60885 // convert everything to numbers so it's fast
60886 var day = 86400000;
60887 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60890 //Roo.log(prevStart);
60892 var today = new Date().clearTime().getTime();
60893 var sel = date.clearTime().getTime();
60894 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60895 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60896 var ddMatch = this.disabledDatesRE;
60897 var ddText = this.disabledDatesText;
60898 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60899 var ddaysText = this.disabledDaysText;
60900 var format = this.format;
60902 var setCellClass = function(cal, cell){
60904 //Roo.log('set Cell Class');
60906 var t = d.getTime();
60911 cell.dateValue = t;
60913 cell.className += " fc-today";
60914 cell.className += " fc-state-highlight";
60915 cell.title = cal.todayText;
60918 // disable highlight in other month..
60919 cell.className += " fc-state-highlight";
60924 //cell.className = " fc-state-disabled";
60925 cell.title = cal.minText;
60929 //cell.className = " fc-state-disabled";
60930 cell.title = cal.maxText;
60934 if(ddays.indexOf(d.getDay()) != -1){
60935 // cell.title = ddaysText;
60936 // cell.className = " fc-state-disabled";
60939 if(ddMatch && format){
60940 var fvalue = d.dateFormat(format);
60941 if(ddMatch.test(fvalue)){
60942 cell.title = ddText.replace("%0", fvalue);
60943 cell.className = " fc-state-disabled";
60947 if (!cell.initialClassName) {
60948 cell.initialClassName = cell.dom.className;
60951 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60956 for(; i < startingPos; i++) {
60957 cells[i].dayName = (++prevStart);
60958 Roo.log(textEls[i]);
60959 d.setDate(d.getDate()+1);
60961 //cells[i].className = "fc-past fc-other-month";
60962 setCellClass(this, cells[i]);
60967 for(; i < days; i++){
60968 intDay = i - startingPos + 1;
60969 cells[i].dayName = (intDay);
60970 d.setDate(d.getDate()+1);
60972 cells[i].className = ''; // "x-date-active";
60973 setCellClass(this, cells[i]);
60977 for(; i < 42; i++) {
60978 //textEls[i].innerHTML = (++extraDays);
60980 d.setDate(d.getDate()+1);
60981 cells[i].dayName = (++extraDays);
60982 cells[i].className = "fc-future fc-other-month";
60983 setCellClass(this, cells[i]);
60986 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60988 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60990 // this will cause all the cells to mis
60993 for (var r = 0;r < 6;r++) {
60994 for (var c =0;c < 7;c++) {
60995 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60999 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
61000 for(i=0;i<cells.length;i++) {
61002 this.cells.elements[i].dayName = cells[i].dayName ;
61003 this.cells.elements[i].className = cells[i].className;
61004 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
61005 this.cells.elements[i].title = cells[i].title ;
61006 this.cells.elements[i].dateValue = cells[i].dateValue ;
61012 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
61013 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
61015 ////if(totalRows != 6){
61016 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
61017 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
61020 this.fireEvent('monthchange', this, date);
61025 * Returns the grid's SelectionModel.
61026 * @return {SelectionModel}
61028 getSelectionModel : function(){
61029 if(!this.selModel){
61030 this.selModel = new Roo.grid.CellSelectionModel();
61032 return this.selModel;
61036 this.eventStore.load()
61042 findCell : function(dt) {
61043 dt = dt.clearTime().getTime();
61045 this.cells.each(function(c){
61046 //Roo.log("check " +c.dateValue + '?=' + dt);
61047 if(c.dateValue == dt){
61057 findCells : function(rec) {
61058 var s = rec.data.start_dt.clone().clearTime().getTime();
61060 var e= rec.data.end_dt.clone().clearTime().getTime();
61063 this.cells.each(function(c){
61064 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
61066 if(c.dateValue > e){
61069 if(c.dateValue < s){
61078 findBestRow: function(cells)
61082 for (var i =0 ; i < cells.length;i++) {
61083 ret = Math.max(cells[i].rows || 0,ret);
61090 addItem : function(rec)
61092 // look for vertical location slot in
61093 var cells = this.findCells(rec);
61095 rec.row = this.findBestRow(cells);
61097 // work out the location.
61101 for(var i =0; i < cells.length; i++) {
61109 if (crow.start.getY() == cells[i].getY()) {
61111 crow.end = cells[i];
61127 for (var i = 0; i < cells.length;i++) {
61128 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
61135 clearEvents: function() {
61137 if (!this.eventStore.getCount()) {
61140 // reset number of rows in cells.
61141 Roo.each(this.cells.elements, function(c){
61145 this.eventStore.each(function(e) {
61146 this.clearEvent(e);
61151 clearEvent : function(ev)
61154 Roo.each(ev.els, function(el) {
61155 el.un('mouseenter' ,this.onEventEnter, this);
61156 el.un('mouseleave' ,this.onEventLeave, this);
61164 renderEvent : function(ev,ctr) {
61166 ctr = this.view.el.select('.fc-event-container',true).first();
61170 this.clearEvent(ev);
61176 var cells = ev.cells;
61177 var rows = ev.rows;
61178 this.fireEvent('eventrender', this, ev);
61180 for(var i =0; i < rows.length; i++) {
61184 cls += ' fc-event-start';
61186 if ((i+1) == rows.length) {
61187 cls += ' fc-event-end';
61190 //Roo.log(ev.data);
61191 // how many rows should it span..
61192 var cg = this.eventTmpl.append(ctr,Roo.apply({
61195 }, ev.data) , true);
61198 cg.on('mouseenter' ,this.onEventEnter, this, ev);
61199 cg.on('mouseleave' ,this.onEventLeave, this, ev);
61200 cg.on('click', this.onEventClick, this, ev);
61204 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
61205 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
61208 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
61209 cg.setWidth(ebox.right - sbox.x -2);
61213 renderEvents: function()
61215 // first make sure there is enough space..
61217 if (!this.eventTmpl) {
61218 this.eventTmpl = new Roo.Template(
61219 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
61220 '<div class="fc-event-inner">' +
61221 '<span class="fc-event-time">{time}</span>' +
61222 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
61224 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
61232 this.cells.each(function(c) {
61233 //Roo.log(c.select('.fc-day-content div',true).first());
61234 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
61237 var ctr = this.view.el.select('.fc-event-container',true).first();
61240 this.eventStore.each(function(ev){
61242 this.renderEvent(ev);
61246 this.view.layout();
61250 onEventEnter: function (e, el,event,d) {
61251 this.fireEvent('evententer', this, el, event);
61254 onEventLeave: function (e, el,event,d) {
61255 this.fireEvent('eventleave', this, el, event);
61258 onEventClick: function (e, el,event,d) {
61259 this.fireEvent('eventclick', this, el, event);
61262 onMonthChange: function () {
61266 onLoad: function () {
61268 //Roo.log('calendar onload');
61270 if(this.eventStore.getCount() > 0){
61274 this.eventStore.each(function(d){
61279 if (typeof(add.end_dt) == 'undefined') {
61280 Roo.log("Missing End time in calendar data: ");
61284 if (typeof(add.start_dt) == 'undefined') {
61285 Roo.log("Missing Start time in calendar data: ");
61289 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
61290 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
61291 add.id = add.id || d.id;
61292 add.title = add.title || '??';
61300 this.renderEvents();
61310 render : function ()
61314 if (!this.view.el.hasClass('course-timesheet')) {
61315 this.view.el.addClass('course-timesheet');
61317 if (this.tsStyle) {
61322 Roo.log(_this.grid.view.el.getWidth());
61325 this.tsStyle = Roo.util.CSS.createStyleSheet({
61326 '.course-timesheet .x-grid-row' : {
61329 '.x-grid-row td' : {
61330 'vertical-align' : 0
61332 '.course-edit-link' : {
61334 'text-overflow' : 'ellipsis',
61335 'overflow' : 'hidden',
61336 'white-space' : 'nowrap',
61337 'cursor' : 'pointer'
61342 '.de-act-sup-link' : {
61343 'color' : 'purple',
61344 'text-decoration' : 'line-through'
61348 'text-decoration' : 'line-through'
61350 '.course-timesheet .course-highlight' : {
61351 'border-top-style': 'dashed !important',
61352 'border-bottom-bottom': 'dashed !important'
61354 '.course-timesheet .course-item' : {
61355 'font-family' : 'tahoma, arial, helvetica',
61356 'font-size' : '11px',
61357 'overflow' : 'hidden',
61358 'padding-left' : '10px',
61359 'padding-right' : '10px',
61360 'padding-top' : '10px'
61368 monitorWindowResize : false,
61369 cellrenderer : function(v,x,r)
61374 xtype: 'CellSelectionModel',
61381 beforeload : function (_self, options)
61383 options.params = options.params || {};
61384 options.params._month = _this.monthField.getValue();
61385 options.params.limit = 9999;
61386 options.params['sort'] = 'when_dt';
61387 options.params['dir'] = 'ASC';
61388 this.proxy.loadResponse = this.loadResponse;
61390 //this.addColumns();
61392 load : function (_self, records, options)
61394 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
61395 // if you click on the translation.. you can edit it...
61396 var el = Roo.get(this);
61397 var id = el.dom.getAttribute('data-id');
61398 var d = el.dom.getAttribute('data-date');
61399 var t = el.dom.getAttribute('data-time');
61400 //var id = this.child('span').dom.textContent;
61403 Pman.Dialog.CourseCalendar.show({
61407 productitem_active : id ? 1 : 0
61409 _this.grid.ds.load({});
61414 _this.panel.fireEvent('resize', [ '', '' ]);
61417 loadResponse : function(o, success, response){
61418 // this is overridden on before load..
61420 Roo.log("our code?");
61421 //Roo.log(success);
61422 //Roo.log(response)
61423 delete this.activeRequest;
61425 this.fireEvent("loadexception", this, o, response);
61426 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61431 result = o.reader.read(response);
61433 Roo.log("load exception?");
61434 this.fireEvent("loadexception", this, o, response, e);
61435 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61438 Roo.log("ready...");
61439 // loop through result.records;
61440 // and set this.tdate[date] = [] << array of records..
61442 Roo.each(result.records, function(r){
61444 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61445 _this.tdata[r.data.when_dt.format('j')] = [];
61447 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61450 //Roo.log(_this.tdata);
61452 result.records = [];
61453 result.totalRecords = 6;
61455 // let's generate some duumy records for the rows.
61456 //var st = _this.dateField.getValue();
61458 // work out monday..
61459 //st = st.add(Date.DAY, -1 * st.format('w'));
61461 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61463 var firstOfMonth = date.getFirstDayOfMonth();
61464 var days = date.getDaysInMonth();
61466 var firstAdded = false;
61467 for (var i = 0; i < result.totalRecords ; i++) {
61468 //var d= st.add(Date.DAY, i);
61471 for(var w = 0 ; w < 7 ; w++){
61472 if(!firstAdded && firstOfMonth != w){
61479 var dd = (d > 0 && d < 10) ? "0"+d : d;
61480 row['weekday'+w] = String.format(
61481 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61482 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61484 date.format('Y-m-')+dd
61487 if(typeof(_this.tdata[d]) != 'undefined'){
61488 Roo.each(_this.tdata[d], function(r){
61492 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61493 if(r.parent_id*1>0){
61494 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61497 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61498 deactive = 'de-act-link';
61501 row['weekday'+w] += String.format(
61502 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61504 r.product_id_name, //1
61505 r.when_dt.format('h:ia'), //2
61515 // only do this if something added..
61517 result.records.push(_this.grid.dataSource.reader.newRow(row));
61521 // push it twice. (second one with an hour..
61525 this.fireEvent("load", this, o, o.request.arg);
61526 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61528 sortInfo : {field: 'when_dt', direction : 'ASC' },
61530 xtype: 'HttpProxy',
61533 url : baseURL + '/Roo/Shop_course.php'
61536 xtype: 'JsonReader',
61553 'name': 'parent_id',
61557 'name': 'product_id',
61561 'name': 'productitem_id',
61579 click : function (_self, e)
61581 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61582 sd.setMonth(sd.getMonth()-1);
61583 _this.monthField.setValue(sd.format('Y-m-d'));
61584 _this.grid.ds.load({});
61590 xtype: 'Separator',
61594 xtype: 'MonthField',
61597 render : function (_self)
61599 _this.monthField = _self;
61600 // _this.monthField.set today
61602 select : function (combo, date)
61604 _this.grid.ds.load({});
61607 value : (function() { return new Date(); })()
61610 xtype: 'Separator',
61616 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61626 click : function (_self, e)
61628 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61629 sd.setMonth(sd.getMonth()+1);
61630 _this.monthField.setValue(sd.format('Y-m-d'));
61631 _this.grid.ds.load({});
61644 * Ext JS Library 1.1.1
61645 * Copyright(c) 2006-2007, Ext JS, LLC.
61647 * Originally Released Under LGPL - original licence link has changed is not relivant.
61650 * <script type="text/javascript">
61654 * @class Roo.LoadMask
61655 * A simple utility class for generically masking elements while loading data. If the element being masked has
61656 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61657 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61658 * element's UpdateManager load indicator and will be destroyed after the initial load.
61660 * Create a new LoadMask
61661 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61662 * @param {Object} config The config object
61664 Roo.LoadMask = function(el, config){
61665 this.el = Roo.get(el);
61666 Roo.apply(this, config);
61668 this.store.on('beforeload', this.onBeforeLoad, this);
61669 this.store.on('load', this.onLoad, this);
61670 this.store.on('loadexception', this.onLoadException, this);
61671 this.removeMask = false;
61673 var um = this.el.getUpdateManager();
61674 um.showLoadIndicator = false; // disable the default indicator
61675 um.on('beforeupdate', this.onBeforeLoad, this);
61676 um.on('update', this.onLoad, this);
61677 um.on('failure', this.onLoad, this);
61678 this.removeMask = true;
61682 Roo.LoadMask.prototype = {
61684 * @cfg {Boolean} removeMask
61685 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61686 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61688 removeMask : false,
61690 * @cfg {String} msg
61691 * The text to display in a centered loading message box (defaults to 'Loading...')
61693 msg : 'Loading...',
61695 * @cfg {String} msgCls
61696 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61698 msgCls : 'x-mask-loading',
61701 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61707 * Disables the mask to prevent it from being displayed
61709 disable : function(){
61710 this.disabled = true;
61714 * Enables the mask so that it can be displayed
61716 enable : function(){
61717 this.disabled = false;
61720 onLoadException : function()
61722 Roo.log(arguments);
61724 if (typeof(arguments[3]) != 'undefined') {
61725 Roo.MessageBox.alert("Error loading",arguments[3]);
61729 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61730 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61737 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61740 onLoad : function()
61742 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61746 onBeforeLoad : function(){
61747 if(!this.disabled){
61748 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61753 destroy : function(){
61755 this.store.un('beforeload', this.onBeforeLoad, this);
61756 this.store.un('load', this.onLoad, this);
61757 this.store.un('loadexception', this.onLoadException, this);
61759 var um = this.el.getUpdateManager();
61760 um.un('beforeupdate', this.onBeforeLoad, this);
61761 um.un('update', this.onLoad, this);
61762 um.un('failure', this.onLoad, this);
61767 * Ext JS Library 1.1.1
61768 * Copyright(c) 2006-2007, Ext JS, LLC.
61770 * Originally Released Under LGPL - original licence link has changed is not relivant.
61773 * <script type="text/javascript">
61778 * @class Roo.XTemplate
61779 * @extends Roo.Template
61780 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61782 var t = new Roo.XTemplate(
61783 '<select name="{name}">',
61784 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61788 // then append, applying the master template values
61791 * Supported features:
61796 {a_variable} - output encoded.
61797 {a_variable.format:("Y-m-d")} - call a method on the variable
61798 {a_variable:raw} - unencoded output
61799 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61800 {a_variable:this.method_on_template(...)} - call a method on the template object.
61805 <tpl for="a_variable or condition.."></tpl>
61806 <tpl if="a_variable or condition"></tpl>
61807 <tpl exec="some javascript"></tpl>
61808 <tpl name="named_template"></tpl> (experimental)
61810 <tpl for="."></tpl> - just iterate the property..
61811 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61815 Roo.XTemplate = function()
61817 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61824 Roo.extend(Roo.XTemplate, Roo.Template, {
61827 * The various sub templates
61832 * basic tag replacing syntax
61835 * // you can fake an object call by doing this
61839 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61842 * compile the template
61844 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61847 compile: function()
61851 s = ['<tpl>', s, '</tpl>'].join('');
61853 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61854 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61855 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61856 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61857 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61862 while(true == !!(m = s.match(re))){
61863 var forMatch = m[0].match(nameRe),
61864 ifMatch = m[0].match(ifRe),
61865 execMatch = m[0].match(execRe),
61866 namedMatch = m[0].match(namedRe),
61871 name = forMatch && forMatch[1] ? forMatch[1] : '';
61874 // if - puts fn into test..
61875 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61877 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61882 // exec - calls a function... returns empty if true is returned.
61883 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61885 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61893 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61894 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61895 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61898 var uid = namedMatch ? namedMatch[1] : id;
61902 id: namedMatch ? namedMatch[1] : id,
61909 s = s.replace(m[0], '');
61911 s = s.replace(m[0], '{xtpl'+ id + '}');
61916 for(var i = tpls.length-1; i >= 0; --i){
61917 this.compileTpl(tpls[i]);
61918 this.tpls[tpls[i].id] = tpls[i];
61920 this.master = tpls[tpls.length-1];
61924 * same as applyTemplate, except it's done to one of the subTemplates
61925 * when using named templates, you can do:
61927 * var str = pl.applySubTemplate('your-name', values);
61930 * @param {Number} id of the template
61931 * @param {Object} values to apply to template
61932 * @param {Object} parent (normaly the instance of this object)
61934 applySubTemplate : function(id, values, parent)
61938 var t = this.tpls[id];
61942 if(t.test && !t.test.call(this, values, parent)){
61946 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61947 Roo.log(e.toString());
61953 if(t.exec && t.exec.call(this, values, parent)){
61957 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61958 Roo.log(e.toString());
61963 var vs = t.target ? t.target.call(this, values, parent) : values;
61964 parent = t.target ? values : parent;
61965 if(t.target && vs instanceof Array){
61967 for(var i = 0, len = vs.length; i < len; i++){
61968 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61970 return buf.join('');
61972 return t.compiled.call(this, vs, parent);
61974 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61975 Roo.log(e.toString());
61976 Roo.log(t.compiled);
61981 compileTpl : function(tpl)
61983 var fm = Roo.util.Format;
61984 var useF = this.disableFormats !== true;
61985 var sep = Roo.isGecko ? "+" : ",";
61986 var undef = function(str) {
61987 Roo.log("Property not found :" + str);
61991 var fn = function(m, name, format, args)
61993 //Roo.log(arguments);
61994 args = args ? args.replace(/\\'/g,"'") : args;
61995 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61996 if (typeof(format) == 'undefined') {
61997 format= 'htmlEncode';
61999 if (format == 'raw' ) {
62003 if(name.substr(0, 4) == 'xtpl'){
62004 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
62007 // build an array of options to determine if value is undefined..
62009 // basically get 'xxxx.yyyy' then do
62010 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
62011 // (function () { Roo.log("Property not found"); return ''; })() :
62016 Roo.each(name.split('.'), function(st) {
62017 lookfor += (lookfor.length ? '.': '') + st;
62018 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
62021 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
62024 if(format && useF){
62026 args = args ? ',' + args : "";
62028 if(format.substr(0, 5) != "this."){
62029 format = "fm." + format + '(';
62031 format = 'this.call("'+ format.substr(5) + '", ';
62035 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
62039 // called with xxyx.yuu:(test,test)
62041 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
62043 // raw.. - :raw modifier..
62044 return "'"+ sep + udef_st + name + ")"+sep+"'";
62048 // branched to use + in gecko and [].join() in others
62050 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
62051 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
62054 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
62055 body.push(tpl.body.replace(/(\r\n|\n)/g,
62056 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
62057 body.push("'].join('');};};");
62058 body = body.join('');
62061 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
62063 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
62069 applyTemplate : function(values){
62070 return this.master.compiled.call(this, values, {});
62071 //var s = this.subs;
62074 apply : function(){
62075 return this.applyTemplate.apply(this, arguments);
62080 Roo.XTemplate.from = function(el){
62081 el = Roo.getDom(el);
62082 return new Roo.XTemplate(el.value || el.innerHTML);